Heres what I'm trying to accomplish:
I want to check if the tag already exists. If it does I want to use the existing tag for the tag_join record, rather than creating a new tag record.
Here is my current code, which isn't working.
class Tag < ActiveRecord :: Base
belongs_to :user
belongs_to :tag_join
belongs_to :post
before_create :check_exists
def check_exists
tag = Tag.where(:name => self.name, :user_id => current_user.id)
if tag.nil?
tag = Tag.create(:name => self.name, :user_id => current_user.id)
end
end
end
This doesn't work though, I'm getting an error upon task creation...(the server is actually just timing out - I don't receive a specific error).
Any ideas?
Tokland said I was creating an infinite loop by telling it to create tag again - so I tried this:
def check_exists
tag = Tag.find_by_name_and_user_id(:name => self.name, :user_id => current_user.id)
if tag != nil
self.id = tag.id
end
end
And still get the server timeout
Edit: I'm not sure if this matters, but the way the tags are being added is similar to "http://railscasts.com/episodes/73-complex-forms-part-1
they're nested in the post form, and use something like this:
def tag_attributes=(tag_attributes)
tag_attributes.each do |attributes|
tags.build(attributes)
end
end
I'm wondering if this is stopping this whole thing from working? Also, using current_user.id in the model definitely seems to be an issue...
EDIT:
Something I have figured out: this had to change, the format we were using before was incorrect syntax - generally used for a .where method.
def check_exists
@tag = Tag.find_by_name_and_user_id(self.name, self.user_id)
if @tag != nil
#return false
#self=@tag
end
end
The problem now is this, I can learn if it the tag already exists. But then what? If I go with the return false option, there is an error upon post creation, and the join record isn't created... The other option "self=@tag" obviously just doesn't work.
Rails validation defines valid states for each of your Active Record model classes. They are used to ensure that only valid details are entered into your database. Rails make it easy to add validations to your model classes and allows you to create your own validation methods as well.
You're going to find it hard to to this from within the Tag model. It seems like what you want is to update the Post using nested attributes, like so:
post = Post.create
post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
This is actually pretty simple to do by using a virtual attribute setter method:
class Post < AR::Base
has_many :tags
def tags_attributes=(hash)
hash.each do |sequence,tag_values|
tags << Tag.find_or_create_by_name_and_user_id(tag_values[:name],\
tag_values[:user_id])
end
end
> post = Post.create
> post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
> Tag.count # => 1
# updating again does not add dups
> post.update_attributes(:tags_attributes=>{"0"=>{:name=>"fish",:user_id=>"37"}})
> Tag.count # => 1
There's a find_or_create_by_
function built right in to Rails
# No 'Summer' tag exists
Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
# Now the 'Summer' tag does exist
Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
http://api.rubyonrails.org/classes/ActiveRecord/Base.html (under Dynamic attribute-based finders)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With