如何循环连接表

时间:2017-03-14 10:47:03

标签: ruby-on-rails join activerecord

我的模特:

分类

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 #<Categorization:0x007f2cf6ee49e8>。所以,它遍历Categorization。循环连接games表的最佳方法是什么?感谢。

2 个答案:

答案 0 :(得分:1)

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

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

使用@provider.categorizations.joins(:games)你不是要求游戏。您要求进行分类,并与游戏表进行联接。此连接通常允许按游戏属性进行过滤。

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

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

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

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

答案 1 :(得分:0)

我猜'标题'是游戏的一个属性,而不是分类,所以你需要返回一个游戏数组,或者在末尾添加一个select来将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 %>