如何编写连接Rails ActiveRecord_Relation?

时间:2014-10-31 16:33:19

标签: ruby-on-rails ruby

> u = User.first
> u.viewable_cars
OR
> Car.for(u)

会让我只看到用户有权查看的车辆,但不是他拥有的车辆!用于u.viewable_cars&的irb中的SQL Car.for(u),相同,属于用户的id为1到50的汽车根本不会被调用:

SELECT "cars".* FROM "cars" INNER JOIN "permissions" ON "permissions"."thing_id" = "cars"."id"     AND "permissions"."thing_type" = $1 WHERE ((cars.user_id = 1) OR (permissions.action = 'view' AND permissions.user_id = 1))  ORDER BY created_at DESC  [["thing_type", "Car"]]
=> #<ActiveRecord::Relation [#<Car id: 52, content: "sport edition", name: "BMW", user_id: 2, created_at: "2014-11-01 04:58:19", updated_at: "2014-11-01 04:58:19">, #<Car id: 51, content: "super sport car", name: "BMW M6", user_id: 3, created_at: "2014-11-01 04:44:31", updated_at: "2014-11-01 04:44:31">]>

class Car < ActiveRecord::Base
   belongs_to :user
   has_many :permissions, as: :thing

   default_scope -> { order('created_at DESC') }
   validates :user_id, presence: true
   validates :name, presence: true, length: { maximum: 50 }, uniqueness: true
   validates :content, length: { maximum: 300 }, allow_blank: true

   scope :viewable_by, ->(user) do
      joins(:permissions).where(permissions: { action: "view",
                                         user_id: user.id })
   end

  scope :for, ->(user) do
     joins(:permissions).
     where("(cars.user_id = :user_id) OR (permissions.action = 'view' AND permissions.user_id = :user_id)", user_id: user.id)
  end
end

class User < ActiveRecord::Base
   ...
   has_many :cars, dependent: :destroy

   has_many :permissions

   has_many :viewable_cars, ->(user) { joins(:permissions).
       where("(cars.user_id = :user_id) OR (permissions.action = 'view' AND permissions.user_id   = :user_id)", user_id: user.id) },
       class_name: "Car"

   def viewable_cars
      Car.for(self)
   end
 end


 class Permission < ActiveRecord::Base
   belongs_to :user
   belongs_to :thing, polymorphic: true
 end

 Rails.application.routes.draw do
   resources :users do
     resources :cars
   end
end

1 个答案:

答案 0 :(得分:0)

car.rb 中的范围for应为:

scope :for, ->(user) do
  joins("LEFT OUTER JOIN permissions ON permissions.thing_id = cars.id AND permissions.thing_type = 'Car'").where("(cars.user_id = :user_id) OR (permissions.action = 'view' AND permissions.user_id = :user_id)", user_id: user.id)
end

现在你可以:Car.for(current_user).find(params[:id])。但是,这看起来像是反模式。因此,您可以在 user.rb 中创建另一个关联,如下所示:

Rails 4

has_many :viewable_cars, ->(user) { 
         joins("LEFT OUTER JOIN permissions ON permissions.thing_id = cars.id AND permissions.thing_type = 'Car'").
         where("(cars.user_id = :user_id) OR (permissions.action = 'view' AND permissions.user_id = :user_id)", user_id: user.id) }, 
  class_name: 'Car'

Rails 3 (无法找到更好的方法,例如:关联):

def viewable_cars
  Car.for(self)
end

这样您就可以为用户获取所有汽车:

current_user.viewable_cars

在控制器中:

@car = current_user.viewable_cars.find(params[:id])