This will come in quite handy on the next project - as always with your screencasts.
<3
Thank you for your great screencast, it will be useful to me shortly. :)
Thanks for this great episode :) However, I did have one question. What happens if the virtual attribute model fails validation?
Dear Ryan,
This episode is as great as it always use to be. I have one doubt though...
You have defined task_names as writer. It means it wont be defining
def task_names=(name)
@task_names = name
end
Then how does its value get assigned?
Thanks,
Madan Kumar Rajan
and don't forget that this code also allows you to remove tags from an article.
and be aware of unused tags if you heavily add and remove tags, since only taggings are destroyed.
Boo to sniffles, get well soon.
That's the first time I've ever seen f.error_messages.. How long has that been available?
Madan Kumar Rajan,
attr_writer creates that code automatically. Search about meta-programming :)
This code could potentially lead to orphaned tags and taggings, couldn't it? I don't know what meta-magic goes on behind the stage, but the code for cleaning up after yourself does seem to be missing?
Otherwise, great job :)
Two years ago this stuff could be called complex, but Ryan, as you just say, today we are using it in all our everyday projects.
These days it really shouldn't be called hard or complex, we probably need a different approach to the problem.
@J, good question. Here Tag doesn't have any validations (it is too simple), but if there are validations on the model you'll definitely need to take that into consideration.
One solution is to do "create!" (with a bang) to ensure an exception is raised if the validation fails. However this is not pretty to the end user. Unfortunately I don't know of an easy way to handle validations in a pretty way here.
@Vincent, f.error_messages has been around for quite some time, I think since Rails 2.0 but I'm not positive.
@Robin, It should not orphan any Tagging records (the tags= method takes care of this), but Tag models will continue to exist even if they do not have articles assigned to them.
I don't think that is much of an issue here, but there are a couple ways around this. One is to add an after_destroy hook on tagging to check if it is the last one and remove the tag as well. Alternatively you could set up an external recurring task to loop through all tags and remove empty ones.
Great screencast.
Short but informative and to the point.
Chris
Thanks for this Ryan!
I'm trying to use virtual attributes on a model that maintains a 'duration' field, which is an integer of seconds. In my model I'd like to be able to represent this duration value as 'hours' & 'minutes'. The model saves correctly, however I can't seem to find a way to initialise hours & minutes from the database. Could you help?
http://pastie.org/524093
Are you using :value for your textfields? :value=>@course.duration/3600
AWESOME :D
Just when I was trying to remember how to do this, railscasts to the rescue
Hi!
I like that stylesheet. Is it made by you and can I use it for my testing?
Keep up with the good work!
Felix
Man I love this site. Every single screencast has somehow been included in a project i'm working on, and this one is no exception :)
Now taking this further, how would i go about doing a Article.find_by_tag_name method or named_scope?
Any help would be greatly appreciated.
Thx.
Well i think i might have found a way.. I've created a named_scope in the Articles model:
named_scope :find_by_tag, lambda { |*args| {:include => :tags, :conditions => ["tags.name ILIKE ?", '%'+args.first+'%']} }
Not sure if it's the best way (probably not) but seems to work... any better ideas?
Karim:
sorry if this is not what you are looking for but what about:
def find_by_tag name
Tag.find_by_name(name).articles
end
Thanks for making quality screen casts! They are always a big help!
I'm attempting to clean up orphaned tags by using a after_destroy hook, but it doesn't seem to even be fired?
Does the virtual writer not fire the destroy events?
Thanks!
Hi Ryan, would it not be better to use a before_save callback to call assign_tags, and then use find_or_initialize_by_name instead of find_or_create_by_name. That way, the tags all get saved in one atomic action.
I have used this code in my own app but took it one step further by adding a counter cache to the tags table called taggings_count. This is where the problems start. It increments the count when taggings are added but does not decrement the count when taggings are deleted. Any suggestions would be appreciated.
Great cast. Great site. I wake up on Mondays ready to watch another cast.
I recently needed to start using tagging in my application, so I immediately came to railscasts.com
Instead of articles, my model is entry. Companies have many entries. Entries have many tags. A tag belongs to a company. A user belongs to a company. I would like to track the tags by company by adding a company_id to the tag table. What code would I need to modify to be able to add the company_id that is a hidden field in the form?
@Brad. I have the same problem with decrementing the counters. I even tried adding before_destroy and after_destroy to the taggings, but they don't even get called. I guess that they are deleted and not destroyed. Thoughts Ryan?
I managed to get the counter caches to decrement. It's ugly and probably excessive. But it does work.
def assign_tags
if @tag_names
new_tags = @tag_names.split(/\s+/).map do |name|
Tag.find_or_create_by_name(name)
end
# destroy taggings to decrement counter cache
self.taggings.each do |t|
t.destroy if !new_tags.collect(&:id).include?(t.tag_id)
end
# assign any new tags
self.tags = new_tags
end
end







