Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何使用第二个表中的列值(如果存在)覆盖表列值?_Ruby On Rails - Fatal编程技术网

Ruby on rails 如何使用第二个表中的列值(如果存在)覆盖表列值?

Ruby on rails 如何使用第二个表中的列值(如果存在)覆盖表列值?,ruby-on-rails,Ruby On Rails,我正在构建一个电子商务应用程序,您可以在其中为产品设置特定于用户的价格。如果未为特定用户设置特定产品的价格,则会显示默认产品价格 它工作得很好,但我正在寻找更有效的解决方案,因为我对当前的解决方案不满意 表格: @products = Product.with_user_prices(current_user) <% @products.each do |product| %> <%= product.price_for_user %> <% end %>

我正在构建一个电子商务应用程序,您可以在其中为产品设置特定于用户的价格。如果未为特定用户设置特定产品的价格,则会显示默认产品价格

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

表格:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>
  • 使用者
  • 产品(所有产品信息+常规价格)
  • 价格(用户id、产品id、用户价格)
型号:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>
class用户
类产品
class Price
如何在controller中获得所有具有用户特定价格的产品:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>
@products=产品。具有用户价格(当前用户)
如何在视图中显示它们:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>

正如您所看到的,我目前正在加入价格表,然后在视图中显示用户价格(价格表)(如果存在),否则显示常规价格(产品表)

我希望在一个查询中解决所有问题,根据当前用户,只保留一个具有适当值的价格列

新答案: 请不要将此答案标记为正确答案,因为我基本上只是将Marek的代码和您的代码扩展到我的代码中,因为经过几次尝试,我得出了您已经完成的操作,但我只是将其放在这里,以防它对任何人都有帮助:

app/models/product.rb

class Product < ApplicationRecord
  def self.with_user_prices(user)
    joins(
      sanitize_sql_array([
        "LEFT OUTER JOIN prices on prices.product_id = products.id AND prices.user_id = ?", user.id
      ])
    ).select(
      'products.*',
      'COALESCE(prices.user_price, products.regular_price) AS price_for_user'
    )
  end
end
class Product < ApplicationRecord
  has_many :prices

  def price_for_user(user)
    prices.includes(:user).where(
      users: { id: user.id }
    ).first&.user_price || regular_price
  end
end
查看:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>
查看:

@products = Product.with_user_prices(current_user)
<% @products.each do |product| %>
  <%= product.price_for_user %>
<% end %>
# will perform LEFT OUTER JOIN (to eager load both `prices` and `prices -> user`) preventing N+1 queries
@products = Product.eager_load(prices: :user)
<% @products.each do |product| %>
  <%= product.price_for_user(current_user) %>
<% end %>

您可以使用以下功能:

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 %>


请注意,我简化了
产品。通过使用
includes
稍微简化了\u user\u prices
方法,该方法将生成SQL
左连接
查询,因为存在
价格
的条件

从技术上讲,
Product.includes(prices::user)
默认情况下不会生成
left join
,而是生成三个单独的DB查询。此外,它末尾的
all
也是不必要的。另外,
Product#price_for_user
也不起作用,因为在
Product
实例上没有定义方法
包含
。@MarekLipka hi yes。谢谢你完全正确。我现在正在更新它,改为使用
eager\u load
。此外,您正在对每个
产品执行单独的数据库查询:
价格。包括(:user)。其中(…)
,所以这里有N+1问题。@MarekLipka^我还不确定它是否会对每个产品执行SQL,因为我急切地加载了它。但是,正如你所说,我可能错了。我将在本地rails应用程序上试用它,并相应地调整它。谢谢:)谢谢!我感谢你的努力。它工作正常。这绝对是对我的解决方案的一个很好的升级,朝着我想要的方向发展。我相信@MarekLipka会完善它:)你的数据库引擎是什么?@MarekLipka目前我使用的是开发SQLite3数据库,那么我的答案应该是有效的。如果用户没有任何自定义价格设置,它将返回零,否则:未定义的方法“价格”#