我在rails 4 app中有一个标准的has_many / belongs_to关联。
这是我的佣金代码:
task remove_faked: :environment do
destroyed = Movie.where(fake: true).posters.where("created_at < ?", 1.minute.ago).destroy_all
puts "Done. #{destroyed.length} records deleted."
end
但我收到错误:undefined method posters for #<Movie::ActiveRecord_Relation
我在我的控制台中检查了Poster.last
,它有一个关联的movie_id和相应的电影ID。我也可以在我的应用程序中做关联,如Poster.all.where(movie_id:@ movie.id)。
答案 0 :(得分:2)
movie.rb
has_many :posters, dependent: destroy
poster.rb
belongs_to :movie
任务文件
task remove_faked: :environment do
destroyed = Movie.include(:posters).where(fake: true).where("created_at < ?", 1.minute.ago).destroy_all
puts "Done. #{destroyed.length} records deleted."
end
答案 1 :(得分:0)
替换
destroyed = Movie.where(fake: true).posters.where("created_at < ?", 1.minute.ago).destroy_all
与
destroyed = Movie.includes(:posters).where("fake = ? && posters.created_at < ?", true, 1.minute.ago).references(:posters).destroy_all
这只会破坏满足特定条件的假电影。如果你使用了依赖的:: destroy选项,那么属于正在销毁的电影的海报将与电影一起销毁。
答案 2 :(得分:0)
由于您的评论似乎表明您只想销毁Poster
而不是Movie
s,请尝试以下操作:
class Movie < ActiveRecord::Base
has_many :posters
end
class Poster < ActiveRecord::Base
belongs_to :movie
scope :for_fake_movie, ->{ joins(:movie).where(movie:{fake: true}) }
scope :since,->(time_frame){where("created_at < ?", time_frame)}
end
然后任务看起来像这样
task remove_faked: :environment do
destroyed = Poster.for_fake_movie.since(1.minute.ago).destroy_all
puts "Done. #{destroyed.length} records deleted."
end
作用域使代码更清晰,有助于将业务逻辑移动到模型中,而不是使控制器,视图和rake任务混乱。如果你想删除电影,我会选择
class Movie < ActiveRecord::Base
has_many :posters, dependent: :destroy
scope :fake, ->{where(fake: true) }
scope :posters_since, ->(time_frame){joins(:posters).where("posters.created_at < ?", time_frame)}
end
class Poster < ActiveRecord::Base
belongs_to :movie
end
然后任务将是
task remove_faked: :environment do
destroyed = Movie.fake.posters_since(1.minute.ago).destroy_all
puts "Done. #{destroyed.length} records deleted."
end
答案 3 :(得分:0)
where
会生成一组对象。您的posters
关联是在对象本身上定义的,因此不能以这种方式应用。
我宁愿深入研究有关RDBMS如何工作的一些细节。
首先,我遵循一个简单的规则:查询要接收的类实例。您需要Poster
,但是您正在查询Movie
。我会反过来查询Poster
。
您的数据库中有一个强大的 join 概念,显然,它会在特定条件下将两个表中的行连接在一起。你可以想到它,因为它需要每对行,检查条件,如果它是真的,将组合放入内部缓冲区。我们仍然只选择海报&#39;领域,但现在我们可以使用电影&#39;字段也是:
Poster.joins(:movie) # singular, as in association, belongs_to in this case
这改变了......到目前为止没有。但现在它允许你根据相关电影在海报上施加一些条件。
merge
这样做,它应用范围,甚至可能来自不同的模型。没有会产生无效SQL的连接。不是这个时候!
Poster.joins(:movie).merge(Movie.where(fake: true))
我们在这里得到的是属于fake: true
电影的海报。哇,嗯?不只是把自己的条件打到它上面做你的事情:
Poster.joins(:movie)
.merge(Movie.where(fake: true))
.where("created_at < ?", 1.minute.ago)
.destroy_all