我有以下课程
class State < ActiveRecord::Base
has_many :cities
has_many :products, as: :geography
end
class City < ActiveRecord::Base
has_many :neighborhoods
has_many :products, as: :geography
end
class Neighborhood < ActiveRecord::Base
has_many :products, as: :geography
end
class Product < ActiveRecord::Base
belongs_to :geography, polymorphic: true
end
class User < ActiveRecord::Base
belongs_to :state
end
显然我有另一个class
User
。用户只有权查看他/她products
中的state
(除非用户是admin
,在这种情况下,他/她可以看到所有products
)我如何获得User
的所有产品?
我尝试将has_many, :through
添加到State
,如下所示
has_many :cities_activities, through: :cities, source: :products
has_many :neighborhoods_activities, through: :neighborhoods, source: :products
def owned_activities
self.products + self.cities_activities + self.neighborhoods_activities
end
但是owned_activities
会返回Array
而不是ActiveRecord::Relation
(我需要某种方式返回ActiveRecord::Relation
,因此我可以对其进行申请chained scopes
)。
我正在用if
块修补代码 - 代码变得混乱和丑陋,我怎么能以干净的轨道方式做到这一点?
@JTG建议使用merge
,但显然它不能以嵌套方式工作(或者更多的是三个表/模型):
Started GET "/api/products.json?order=total_cost&page=1&per_page=18" for 127.0.0.1 at 2014-07-20 09:27:29 -0500
Processing by ProductsController#index as JSON
Parameters: {"order"=>"total_cost", "page"=>"1", "per_page"=>"18"}
Geokit is using the domain: localhost
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Role Load (0.3ms) SELECT "roles".* FROM "roles" WHERE "roles"."id" = $1 ORDER BY "roles"."id" ASC LIMIT 1 [["id", 5]]
State Load (0.2ms) SELECT "states".* FROM "states" WHERE "states"."id" = $1 ORDER BY "states"."id" ASC LIMIT 1 [["id", 17]]
(9.2ms) SELECT COUNT(*) FROM "products" INNER JOIN "cities" ON "products"."geography_id" = "cities"."id" AND "products"."geography_type" = 'City' INNER JOIN "polygons" ON "products"."geography_id" = "neighborhoods"."id
" AND "products"."geography_type" = 'Neighborhood' INNER JOIN "cities" ON "neighborhoods"."cities_id" = "cities"."id" WHERE "products"."geography_id" = $1 AND "products"."geography_type" = $2 AND "cities"."states_id" = $1 [["geography_id", 17], ["geography_type", "State"], ["states_id", 17]]
PG::DuplicateAlias: ERROR: table name "cities" specified more than once
: SELECT COUNT(*) FROM "products" INNER JOIN "cities" ON "products"."geography_id" = "cities"."id" AND "products"."geography_type" = 'City' INNER JOIN "neighborhoods" ON "products"."geography_id" = "neighborhoods"."id" AND "products"."geography_type" = 'Neighborhood' INNER JOIN "cities" ON "neighborhoods"."cities_id" = "cities"."id" WHERE "products"."geography_id" = $1 AND "products"."geography_type" = $2 AND "cities"."states_id" = $1
ERROR: table name "cities" specified more than once
-- Clase:
答案 0 :(得分:1)
多态关联不适合这些关系...
You can use a nested has_many
.
class State < ActiveRecord::Base
has_many :cities
has_many :products, through: :cities
end
class City < ActiveRecord::Base
has_many :neighborhoods
has_many :products, through: :neighborhoods
end
class Neighborhood < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :neighborhood
end
class User < ActiveRecord::Base
belongs_to :state
end
然后你应该可以运行user.state.products
更好是将has_many :products, through: :state
添加到user.rb,以便您可以运行user.products
答案 1 :(得分:1)
您不能使用merge将查询与AND
组合在一起,您需要的是SQL OR
查询。遗憾的是,任何ActiveRecord方法都不支持这种方法。您可以使用arel来创建此查询,但由于它将非常复杂并且包含大量子查询,因此我发现通过常规查询找到您需要的ID更容易,然后使用它们。
为此,您可以在State
中实现类似的内容。
class State < ActiveRecord::Base
has_many :cities
has_many :neighborhoods, through: :cities
has_many :products, as: :geography
has_many :city_products, through: :cities, source: :products
has_many :neighborhood_products, through: :neighborhoods, source: :products
def all_products
state_product_ids = product_ids
city_product_ids = city_products.pluck(:id)
neighborhood_product_ids = neighborhood_products.pluck(:id)
all_product_ids = [state_product_ids, city_product_ids, neighborhood_product_ids].flatten.uniq
Product.where(id: all_product_ids)
end
end
您现在可以向用户查询所有产品,例如user.state.all_products
。