我正在尝试仅显示当前用户未标记的品牌实例,即使其他用户已经标记了相同的品牌。类似的东西:
控制器
这是我的控制器代码,即使它应该正常工作,它目前还会返回所有品牌实例。
@brand = current_user.brands.includes(:taggings).where( [ "taggings.id IS NULL OR taggings.tagger_id != ?", current_user.id ] ).order("RANDOM()").first
架构(包括我的联合模型)
create_table "brand_users", :force => true do |t|
t.integer "brand_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "taggings", :force => true do |t|
t.integer "tag_id"
t.integer "taggable_id"
t.string "taggable_type"
t.integer "tagger_id"
t.string "tagger_type"
t.string "context"
t.datetime "created_at"
end
add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", :force => true do |t|
t.string "name"
end
end
答案 0 :(得分:2)
因此,如果你正在使用act-as-taggable-on gem并拥有以下模型:
class User < ActiveRecord::Base
acts_as_tagger
has_many :brand_users
has_many :brands, :through => :brand_users
end
因此,您还可以在模式中使用表格,如:
create_table "users", :force => true do |t|
t.string "name"
end
create_table "brands", :force => true do |t|
t.string "name"
end
然后,以下SQL查询应该有希望做你想要的(?):
SELECT brands.*
FROM brands
WHERE brands.id NOT IN (
SELECT brands.id
FROM brands
INNER JOIN brand_users ON brand_users.brand_id = brands.id
INNER JOIN taggings ON (taggings.tagger_id = brand_users.user_id AND taggings.tagger_type = 'User')
WHERE brand_users.user_id = 1 AND taggings.taggable_id = brand_users.brand_id
)
要将其转换为Rails ORM,如果不对整个子选择SQL字符串进行硬编码,我就无法接近,如:
class Brand < ActiveRecord::Base
has_many :brand_users
has_many :users, :through => :brand_users
scope :has_not_been_tagged_by_user, lambda {|user| where("brands.id NOT IN (SELECT brands.id
FROM brands
INNER JOIN brand_users ON brand_users.brand_id = brands.id
INNER JOIN taggings ON (taggings.tagger_id = brand_users.user_id AND taggings.tagger_type = 'User')
WHERE brand_users.user_id = ? AND taggings.taggable_id = brand_users.brand_id)", user.id) }
end
(我知道你可以这样做,然后使用ruby的.map(&:id).join(',')但是如果这是一个大型的应用程序,我认为你通过将其从数据库中取出,将其转换为一个整数字符串而失去了很多性能把它喂回来(据我所知)。)
然后在你的控制器我认为你会做类似的事情:
@brand = current_user.brands.has_not_been_tagged_by_user(current_user)
顺便说一下,我认为这实际上会执行如下的SQL(是吗?):
SELECT brands.*
FROM users
INNER JOIN brand_users ON brand_users.user_id = users.id
INNER JOIN brands ON brands.id = brand_users.brand_id
WHERE brands.id NOT IN (
SELECT brands.id
FROM brands
INNER JOIN brand_users ON brand_users.brand_id = brands.id
INNER JOIN taggings ON (taggings.tagger_id = brand_users.user_id AND taggings.tagger_type = 'User')
WHERE brand_users.user_id = 1 AND taggings.taggable_id = brand_users.brand_id
) AND users.id = 1
答案 1 :(得分:0)
据我所知,没有SELECT * FROM x WHERE * IS NULL
所以程序可能是唯一的方法。只需在数据库中创建一个过程并从代码中调用它,就不必将SQL放在代码中。
您可以看到此类程序的示例here。