【问题标题】:How to loop through a joined table如何循环连接表
【发布时间】:2017-03-14 10:47:02
【问题描述】:

我拥有的模型:

类别:

class Category < ApplicationRecord
  has_many :categorizations
  has_many :providers, through: :categorizations
  accepts_nested_attributes_for :categorizations
end

提供者:

class Provider < ApplicationRecord
  has_many :categorizations
  has_many :categories, through: :categorizations
  accepts_nested_attributes_for :categorizations
end

分类:

class Categorization < ApplicationRecord
  belongs_to :category
  belongs_to :provider
  has_many :games, dependent: :destroy
  accepts_nested_attributes_for :games
end

游戏:

class Game < ApplicationRecord
  belongs_to :categorization
end

我需要展示属于特定提供商的游戏。我试着这样做:

<% @provider.categorizations.joins(:games).each do |game| %>
 <%= game.title %>
<% end %>

它给了我一个错误:NoMethodError: undefined method 'title' for #&lt;Categorization:0x007f2cf6ee49e8&gt;。所以,它循环通过Categorization。循环连接 games 表的最佳方法是什么?谢谢。

【问题讨论】:

    标签: ruby-on-rails join activerecord


    【解决方案1】:

    首先,您应该在控制器中执行请求,或者更好地从控制器调用范围(在模型中定义)。

    不要忘记 Active Record 只是一个 ORM,一个允许您操作 SQL 的工具。

    @provider.categorizations.joins(:games) 不是在要求游戏。您正在要求分类,并与游戏桌进行 JOIN。这种连接通常是为了允许按游戏属性进行过滤。

    要做你想做的事,你应该做以下事情:

    @games = Game.joins(:categorization).where('categorization.provider_id = ?',@provider.id)

    如您所见,连接不返回分类,它允许我使用分类作为过滤器。

    您应该始终注意 Active Record 生成的 SQL。查看在您的服务器跟踪中生成的 SQL 查询。

    【讨论】:

    • 如你所说:在控制器中,我定义了@games变量,然后它给了我一个错误:ActionView::Template::Error (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "categorization" LINE 1: ...ations"."id" = "games"."categorization_id" WHERE (categoriza... ^ : SELECT "games".* FROM "games" INNER JOIN "categorizations" ON "categorizations"."id" = "games"."categorization_id" WHERE (categorization.provider_id = 2)):
    • 抱歉,刚才打错了:categorization.provider_id 应该是 categorizations.provider_id
    【解决方案2】:

    我猜 'title' 是游戏的一个属性而不是分类,所以您要么需要返回一个游戏数组,要么在末尾添加一个选择以将标题属性拉入分类对象,如下所示:

    <% @provider.categorizations.joins(:games).select('dba.games.title').each do |game| %>
      <%= game.title %>
    <% end %>
    

    只是补充一下-您不应该在视图文件中执行此操作。我什至不在控制器中这样做。我倾向于将这种逻辑封装到一个服务类中,在控制器中实例化它以返回一组结果。控制器应该只传递结果集,然后由视图呈现。

    class Provider < ActiveRecrord::Base
    
        # this could be a scope instead, or in a seperate class which 
        # the provider model delegates to- whatever floats you boat
        def get_games
            # you could use pluck instead, which would return an array of titles
            categorizations.joins(:games).select('dba.games.title')
        end
    end 
    
    class ProviderController < ApplicationController
        def show
            provider = Provide.find(params[:id])
            @games = provider.get_games
        end
    end
    
    <% @games.each do |game| %>
        <%= game.title %>
    <% end %>
    

    【讨论】:

      猜你喜欢
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多