首页 > 解决方案 > 如果存在,如何用第二个表中的列值覆盖表列值?

问题描述

我正在构建电子商务应用程序,您可以在其中为产品设置用户特定的价格。如果没有为特定用户设置特定产品的价格,它将显示默认产品价格。

它工作正常,但我正在寻找更有效的解决方案,因为我对当前的解决方案不满意。

表:

楷模:

class User < ApplicationRecord
  has_many :prices
end
class Product < ApplicationRecord
  has_many :prices
  validates :name, presence: true

  def self.with_user_prices(current_user)
    Product.joins(
      Product.sanitize_sql_array(['LEFT OUTER JOIN prices ON prices.user_id = ?
        AND products.id = prices.product_id', current_user])
    ).select('products.*, prices.user_price')
  end
end
class Price < ApplicationRecord
  belongs_to :product
  belongs_to :user
end

我如何在控制器中获得具有用户特定价格的所有产品:

@products = Product.with_user_prices(current_user)

我如何在视图中显示它们:

<% @products.each do |product| %>

  <%= product.user_price ? product.user_price : product.regular_price %>

<% end %>

如您所见,我目前正在加入价格表,然后在视图中显示 user_price(价格表)(如果存在),否则显示常规价格(产品表)。

我很想在一个查询中解决所有问题,根据 current_user 只保留一个具有适当值的价格列

标签: ruby-on-rails

解决方案


您可以使用SQL COALESCE函数:

class Product < ApplicationRecord
  # ...

  def self.with_user_prices(user)
    includes(:prices).where(prices: { user_id: user.id }).select(
      'products.*, COALESCE(prices.user_price, products.regular_price) as price'
    )
  end
end

然后您可以通过以下方式简单地使用它:

<%= product.price %>

请注意,我Product.with_user_prices通过使用 稍微简化了方法includes,这将生成 SQLLEFT JOIN查询,因为有条件 on prices


推荐阅读