Reputation: 72775
I have three models Article
, Author
, and AuthorLine
presenting relationship between article and its authors, in a many-to-many mapping.
class Article < ActiveRecord::Base
has_many :author_lines, :dependent => :destroy
has_many :authors, :through => :author_lines, :dependent => :destroy, :order => 'author_lines.position'
attr_accessor :author_list
end
class Author < ActiveRecord::Base
has_many :author_lines
has_many :articles, :through => :author_lines
end
class AuthorLine < ActiveRecord::Base
validates :author_id, :article_id, :position, :presence => true
belongs_to :author, :counter_cache => :articles_count
belongs_to :article
end
The AuthorLine
model has an additional attribute position
, which tells the order of authors for an article.
Here is what I am doing to create an article with given author names, in article.rb:
def author_list=(raw)
self.authors.clear
raw.split(',').map(&:strip).each_with_index do |e, i|
next if e.blank?
author = Author.find_or_create_by_name(e)
#1
self.authors << author
#2
# AuthorLine.create(:author_id => author.id, :article_id => self.id, :position => i)
end
end
The problem is I have no idea when to update the position
attributes of corresponding AuthorLine
s. if I remove the line #1 and uncomment the line #2, the created AuthorLine may have a nil arctile_id
since self.id
may not be given.
Upvotes: 0
Views: 1196
Reputation: 1429
I'd probably move the code for creating AuthorLines to an after_create
hook in your Article model. If I understand the problem correctly, something like this should do the trick:
after_create :set_author_line_positions
def set_author_line_positions
self.authors.each_with_index do |author, index|
existing_author_line = AuthorLine.where("author_id = ? and article_id = ?", author.id, article.id).first
if existing_author_line
existing_author_line.update_attributes(:position => index)
else
AuthorLine.create(:author_id => author.id, :article_id => self.id, :position => index)
end
end
end
That way, you only wind up setting the AuthorLine positions after your article is already created and has an ID. This also checks to make sure an AuthorLine has already been created; I believe that an AuthorLine would get created every time an author is added to an article but I like to have very explicit checks in callbacks like this.
Upvotes: 1