Rails: build for difference between relationships

狂风中的少年 提交于 2019-12-24 06:07:53

问题


A doc has many articles and can have many edits.

I want to build an edit for each article up to the total number of @doc.articles. This code works with the first build (i.e., when no edits yet exist).

def editing
  @doc = Doc.find(params[:id])
  unbuilt = @doc.articles - @doc.edits
  unbuilt.reverse.each do |article|
    @doc.edits.build(:body => article.body, :article_id => article.id, :doc_id => @doc.id)
  end
end

But when edits already exist it'll keep those edits and still build for the @doc.articles total, ending up with too many edits and some duplicates if only one article was changed.

I want to put some condition against :article_id which exists in both edits and articles in to say (in pseudocode):

unbuilt = @doc.articles - @doc.edits
unbuilt.where('article_id not in (?)', @doc.edits).reverse.each do |article|
  @doc.edits.build(...)
end

Any help would be excellent! Thank-you so much.


回答1:


You are doing something weird here:

unbuilt = @doc.articles - @doc.edits

You probably want this instead

unbuilt = @doc.articles - @doc.edits.map(&:article)

This works if @doc.articles and @doc.edits are small collections, otherwise a SQL solution would be preferred.

-- EDIT: added explanation --

this piece of Ruby

@doc.edits.map(&:article)

is equivalent to

@doc.edits.map do |edit| edit.article end

the previous one is much more compact and exploits a feature introduced in ruby 1.9

It basically takes a symbol (:article), calls on it the 'to_proc' method (it does this by using the '&' character). You can think of the 'to_proc' method as something very similar to this:

def to_proc
  proc { |object| object.send(self) }
end

In ruby, blocks and procs are generally equivalent (kindof), so this works!



来源:https://stackoverflow.com/questions/17269052/rails-build-for-difference-between-relationships

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!