Ruby on Rails: таблица заказов по значению связанной таблицы - PullRequest
0 голосов
/ 24 октября 2019

Я работаю над проектом Ruby on Rails, сделанным кем-то другим. Мне поручено разрешить сортировку таблиц по столбцам.

В этой конкретной таблице есть столбцы из связанной таблицы. Таблица перечисляет историю транзакций и показывает адрес (и другие столбцы) свойства.

Для доступа к значению отношения тело таблицы использует transaction.property.street_address

Когда столбец таблицыссылка нажата, она отправляет параметры запроса на URL. Поскольку не существует транзакции address.street_address, я получаю ошибку 500.

Столбец street_address находится в таблице связанных свойств, поэтому я не уверен, как сортировать по этому полю

<div class="table-container">
  <table class="table text text--body-3 text--medium">
    <tr class="table__heading text--body-4">
      <% if !current_user.user? %>
        <th>Date</th>
      <% end %>
      <th><%= link_to 'Address', { order: 'street_address', desc: @desc == :asc} %></th>
      <th>Property type</th>
      <th><%= link_to 'Price', { order: 'sales_price', desc: @desc == :asc} %></th>
      <% if !current_user.agent? %>
        <th><%= link_to 'Agent', { order: '', desc: @desc == :asc} %></th>
      <% end %>
      <th>Type</th>
      <th></th>
    </tr>
    <% @transactions.each do |transaction| %>
      <tr class="table__row" data-link-to="<%= property_path(transaction.property) %>">
        <td><%= transaction.sales_date.try(:strftime, '%B %d, %Y') %></td>
        <td class="table__address"><%= transaction.property.street_address %></td>
        <td><%= transaction.property.types.map(&:humanize).join(', ') %></td>
        <td><%= number_to_currency(transaction.sales_price) %></td>
        <% if !current_user.agent? %>
          <td><span><%= transaction.user.full_name %></span></td>
        <% end %>
        <% if transaction.property.for_sale? %>
          <td>Sale</td>
        <% else %>
          <td>Lease</td>
        <% end %>
        <td class="table__more">
          <%= link_to "See the property", property_path(transaction.property), class: 'table__row__details button button--tertiary button--tertiary-small' %>
        </td>
        <td>
      </tr>
    <% end %>
  </table>
</div>

Вот модель транзакции:

class Transaction < ApplicationRecord
  belongs_to :user
  belongs_to :property

  validates :cap_rate, presence: true
  validates :sales_date, presence: true
  validates :sales_price, presence: true
  validates :noi, presence: true

  scope :sold_property, -> do
    joins(:property).where(properties: { for_sale: true })
  end


  scope :sold_before_by_broker_agents, -> (month, broker) do
    joins(:user).where('sales_date < ?', month.end_of_month)
      .merge(User.all_by_parent_id(broker.id))
  end
end

Вот модель свойств:

class Property < ApplicationRecord
  extend FriendlyId
  friendly_id :slug_text, use: :slugged

  PHOTOS_LIMIT = 15

  STATES_MAP = {
    'Alabama' => 'AL', 'Alaska' => 'AK', 'Arizona' => 'AZ', 'Arkansas' => 'AR',
    'California' => 'CA', 'Colorado' => 'CO', 'Connecticut' => 'CT',
    'Delaware' => 'DE', 'District of Columbia' => 'DC', 'Florida' => 'FL',
    'Georgia' => 'GA', 'Hawaii' => 'HI', 'Idaho' => 'ID', 'Illinois' => 'IL',
    'Indiana' => 'IN', 'Iowa' => 'IA', 'Kansas' => 'KS', 'Kentucky' => 'KY',
    'Louisiana' => 'LA','Maine' => 'ME', 'Maryland' => 'MD', 'Massachusetts' => 'MA',
    'Michigan' => 'MI', 'Minnesota' => 'MN', 'Mississippi' => 'MS', 'Missouri' => 'MO',
    'Montana' => 'MT', 'Nebraska' => 'NE', 'Nevada' => 'NV', 'New Hampshire' => 'NH',
    'New Jersey' => 'NJ', 'New Mexico' => 'NM', 'New York' => 'NY', 'North Carolina' => 'NC',
    'North Dakota' => 'ND', 'Ohio' => 'OH', 'Oklahoma' => 'OK', 'Oregon' => 'OR',
    'Pennsylvania' => 'PA', 'Rhode Island' => 'RI', 'South Carolina' => 'SC',
    'South Dakota' => 'SD', 'Tennessee' => 'TN', 'Texas' => 'TX', 'Utah' => 'UT',
    'Vermont' => 'VT', 'Virginia' => 'VA', 'Washington' => 'WA', 'West Virginia' => 'WV',
    'Wisconsin' => 'WI', 'Wyoming' => 'WY'
  }.freeze

  PROPERTY_TYPES  = [:industrial, :retail, :shopping_center, :multifamily,
                     :specialty, :office, :health_care, :hostpitality_or_hotel,
                     :sports_and_entertainment, :land, :general_business, :condominium,
                     :residential_income].freeze

  belongs_to :user
  has_many :viewed_properties
  has_many :last_viewed_by, through: :viewed_properties, source: :user
  has_many :favorite_users_properties
  has_many :favorited_by, through: :favorite_users_properties, source: :user
  has_one :property_transaction, class_name: 'Transaction', dependent: :destroy
  has_many :property_amenities, dependent: :destroy
  has_many :amenities, through: :property_amenities
  has_many :property_highlights, inverse_of: :property, dependent: :destroy
  has_many :unit_prices, inverse_of: :property, dependent: :destroy
  has_many :conversations, dependent: :destroy
  has_many :property_photos, inverse_of: :property, dependent: :destroy
  has_many :brochures, inverse_of: :property, dependent: :destroy

  enum land_location: [:industrial_park, :urban]
  enum rail: [:yes, :no]

  accepts_nested_attributes_for :property_highlights, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :unit_prices, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :property_photos, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :brochures, reject_if: :all_blank, allow_destroy: true

  validate :listing_limit_exceeded, on: :create

  validates :property_type,
            :state,
            :county,
            :municipality,
            :city,
            :zip_code,
            :street_address,
            :listed_at,
            :expires_at,
            :property_status,
            :description,
            :status_date_change,
            :parking,
            :lot_size_units,
            presence: true

  validates :price,
            :building_square_feet,
            :lot_size,
            :units,
            :total_taxes,
            numericality: { greater_than_or_equal_to: 0 }

  validates :year_built, inclusion: { in: 1900..(Date.today.year + 5) }

  validates :for_sale, presence: true, unless: :for_lease?
  validates :for_lease, presence: true, unless: :for_sale?

  validates :ceiling_height, numericality: { greater_than_or_equal_to: 0 }, if: -> { industrial? || office? }
  validates :available_square_feet, numericality: { greater_than_or_equal_to: 0 }, unless: -> { multifamily? || specialty? || residential_income? || land?}
  validates :max_contiguous_square_feet, numericality: { greater_than_or_equal_to: 0 }, if: -> { industrial? || retail? || office? }

  validates :amps_volts_phase,
            :number_of_dock_doors,
            :number_of_drive_in_doors,
            :available_office_square_feet,
            numericality: { greater_than_or_equal_to: 0 }, if: :industrial?
  validates :rail, presence: true, if: :industrial?
  validates :income, :expense, numericality: { greater_than_or_equal_to: 0 }, if: -> { multifamily? || residential_income? }

  validates :office_class, presence: true, if: :office?
  validates :land_location, presence: true, if: :land?

  validates :condominium_units,
            numericality: { greater_than_or_equal_to: 0 }, if: :condominium?

  validates :suite_number, presence: true, if: :condominium?

  validates :flat_fee,
            :percentage_of_sale,
            #:referral_fee,
            allow_blank: true, numericality: { greater_than_or_equal_to: 0 }

  validates :apn, :zoning, presence: true, if: :for_sale?
  validates :terms, presence: true, if: :for_lease?

  geocoded_by :address
  after_validation :geocode, if: :address_changed?

  mount_uploader :cover, CoverUploader
  mount_uploaders :photos, PhotoUploader

  scope :last_viewed_properties, -> (user_id, limit) do
    joins(:viewed_properties)
      .merge(ViewedProperty.order(created_at: :desc).where("viewed_properties.user_id = ?", user_id).limit(limit))
  end

  default_scope { where(:deleted_at => nil) }

  before_validation :set_expires_at

  scope :not_sold, -> (parent_id: nil) do
    if parent_id.present?
      left_joins(:property_transaction)
        .where(users: {parent_id: parent_id})
        .where('transactions.property_id': nil)
    else
      left_joins(:property_transaction)
        .where('transactions.property_id': nil)
    end
  end

  scope :active, -> { where('expires_at >= ?', Time.now) }

  scope :expiring_soon, -> { active.where('expires_at <= ?', 7.days.from_now) }

  def self.property_types
    PROPERTY_TYPES.each_with_index.map { |k, v| [k.to_s, v] }.to_h
  end

  def photos
    property_photos.map(&:image)
  end

  PROPERTY_TYPES.each do |type|
    define_method("#{type}?") do
      types.include?(type.to_s)
    end

    define_method("exclusive_#{type}?") do
      types.include?(type.to_s) && types.size == 1
    end
  end

  def property_type
    types[0]
  end

  def property_type=(value)
    types[0] = value
  end

  def slug_text
    [street_address, city, zip_code].compact.join(', ')
  end

  def state_short
    STATES_MAP[state] || state
  end

  def address
    ['United States', state, county, zip_code, city, street_address].compact.join(', ')
  end

  def address_changed?
    city_changed? || street_address_changed? || state_changed? || county_changed? || zip_code_changed?
  end

  def property_cover
    return self.cover if cover.url
    'example/property1.jpeg'
  end

  def secret_renewal_token
    Digest::SHA256.hexdigest("#{user.authenticatable_salt}#{id}#{expires_at}")
  end

  def listed_at
    self[:listed_at] || Date.today
  end

  private

  def listing_limit_exceeded
    if user.parent_id.present?

      broker_user = User.find(user.parent_id)
      current_subscription = broker_user.subscriptions.active.first
      current_listing = Property.left_joins(:property_transaction, :user)
                          .merge(User.all_by_parent_id(user.parent_id))
                          .where('transactions.property_id': nil)
                          .count
    else
      current_listing = Property.left_joins(:property_transaction, :user).where(user_id: user.id).where('transactions.property_id': nil).count
      current_subscription = user.subscriptions.active.first
    end

    unless current_subscription
      errors.add(:base, "Your subscription has expired")
      return
    end

    listing_limit = current_subscription.plan.listing_limit
    if listing_limit <= current_listing
      errors.add(:base, "Your listing limit is exceeded (current limit is: #{listing_limit})")
    end
  end

  def set_expires_at
    if listed_at
      self.expires_at ||= (listed_at + 30.days)
    end
  end
end

1 Ответ

0 голосов
/ 24 октября 2019

делая здесь некоторые предположения о ваших моделях ...

в модели транзакции:

class Transaction < ActiveRecord::Base
  delegate :street_address, to: property

  ...etc
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...