RailsCasts Pro episodes are now free!

Learn more or hide this

Recent Comments

Avatar

I've using the code from this episode, weirdly enough, no matter I try to remove a task or edit task value, the code "@project.update_attributes(params[:project]) " in project controller has always turned out to be false, therefore redirect me to the edit page, where the task values ain't changed. I've spent a day to figure out what's wrong, still got no clue.

Avatar

Nice work, again.

Have you thought about distributing these screencast files with BitTorrent?

Avatar

I was wondering how this method differs/compares to the one explain here, under "Case Three – Special Queries" (the 3'rd example):

http://www.therailsway.com/2007/3/26/association-proxies-are-your-friend

Thanks again for your casts, they've taught me a lot and I'll be sure to donate.

Avatar

My code is here: http://pastie.caboo.se/110538

I don't see anything out of whack, though I did go to a birthday party last night, hopeful my hangover isn't making me miss something stupid.

Avatar

What version of rails are you using for this Ryan? I have almost the exact same needs (a set of textboxes for a has_many) and I get:

@profile[interest_descriptions] is not allowed as an instance variable name

I am running the 2.0 PR. Any light?

Avatar

For future Googlers, I didn't find the real solution, but what I ended up doing was leveraging the Chronic gem to parse natural language date-time expressions.

Avatar

This might be Edge Rails only, but instead of setting an instance variable for <tt>error_messages_for</tt> you can do this:

<code>
%lt!-- in _task.rhtml --&gt;
&lt;%= error_messages_for(:task, :object =&gt; task) %&gt;
</code>

I've noticed that this method really dislikes date-time select boxes.

Avatar

I have a little bit different situation. In this screencast we have project-task but I have task-project situation (contact-group in my case)

So, the form had been saving even though there were validation errors in Group. valid? saved the day

if @contact.group.valid? && @contact.save
            flash[:notice] = 'New contact has been created'
            redirect_to
         end

In the view:
<% if @contact && @contact.errors %>
<%= error_messages_for 'contact' %>
<% if @contact.group %>
<% @group = @contact.group %>
<%= error_messages_for 'group' %>
<% end %>
<% end %>

Avatar

Thanks for another great episode Ryan

One serious problem I've been running into using this pattern is validations, especially on the child model.

If, for example, the tasks model had this:
validates_presence_of :project_id

Then you will not be able to save the in-memory project. Reason is when the project is asked if it's valid? it'll cascade down and ask it's children tasks if they're all also valid? - if you're enforcing on the task level the need for an existing project_id, then that validation will fail since the parent project has not yet been saved, there's no id.

I would be very curious to see if you or anyone else has found a clean solution to this problem. Recently I've resorted to some nastiness like so:

In the loop in tasks_attributes= method, work-around the fact that .build does not assign a task's .project_id (understandable) but also does NOT assign the task's .project:
tasks.buid(attributes).project = self

Then in the validation in the task model, do this:
validates_presence_of :project_id, :if => lambda {|record| record.project.nil? }

It's not clean, it's not cohesive, but it works. I'd love to hear if someone came up with something better.

I'd also be happy to hear throries regarding why this:
t = some_project.tasks.build :a => :b, :c => :d.....

will not populate t.project - it's obvious that rails knows what the parent of the built task is, do why doesn't it assign it (object-reference wise - has nothing to do with whether the parent is saved or not....)

Avatar

Hi. Another great screencast! Thank you very much!

I'd like to do like a couple of other viewers and announce my interest in a cast about act_as_nested_set.

Thanks again...

Avatar

Thank you for the cast. Instead of complicating things with the destroy logic and doing all nasty stuff, how about a call to link_to_remote to destroy the element?

Avatar

@Ryan, I'll try to download and check it again. But there is something different with this one. The rest are playing OK in vlc player and quicktime alternative, but this one only plays on Apple Quicktime only. By the way, you are one of my personal heroes in the internet. Good job!

Avatar

Retried it and it works! I love it when I look like a crazy person... ;-)

Avatar

Excellent screencast. I've got it working beautifully. Thing is... ordinarily, I'm zebra striping my comments (comments instead of reviews, in my case) with <div class="comment <%= cycle("odd", "even") %>"> in my comment partial. Since the page.insert_html is a single insert, and thus, it never cycles, I'm not getting my zebra striping until I refresh.

How might I go about rewriting my zebra striping code to account for this page insert? And, as a followup, if I wanted to display which number comment it was, something I previously did with each_with_index, how might I get that info as well?

Thanks so much!

Avatar

I've been using a custom environment for beta testing and it works really well. I can have beta testers using an edge version of my code while the production users data is unaffected. I can also give beta testers more info in their error messages.

Avatar

@Ryan, yeah I thought it didn't work when I tried it... (specifically when using the 'conditions' variable twice) Maybe I was doing something else wrong :-O Good to know though, I'll re-visit it, Cheers :-)

Avatar

@Igor, interesting idea. Destroying the tasks each time would probably work, however I hesitate to do this. There may be extra state (such as created_at) that we need to stay persistent. There might be other associations with the task that would be lost as well.

@RainChen, from my experience calling @project.save will only save the tasks if the project itself is new as well. This is why I only handle the callback on after_update. Although I haven't tested this extensively.

@tonghoho, I don't think having two "[]" in a form field name will work properly. Instead you'll have to keep track of the sub tasks separately. Sorry I can't go into detail.

Avatar

@Reza, hmm, I encoded this one the same way I do the others and it plays okay here. Are you still having a problem?

@Jonzo, you should be able to pass additional conditions in the find exactly how you do in your code. Does it not work?

Avatar

I think you mean something like this:

[f, m, l].reject{|i| i.empty?}.compact.join(" ")

Yay Ruby. ^.^

Avatar

You can have multiple link tags. This is even used in the W3C standards to have multiple stylesheets specified for different medias, or simply to allow choice of stylesheets. (In Firefox, this shows up in the View Menu -> Page Style sub-menu.)

Avatar

I've went a bit further: I have two helpers, access_denied() and action_denied() that put appropriate output; they now both have the title() call in them to set the title correctly, which is really nice. :)

Avatar

Opps. I missed a set of brakets. It should look like this:

<% fields_for "project[task_attributes][requirement_attributes][]", requirement do |requirement_form| %> (Empty set at end)

Avatar

@Mark

Alright, I think I have the issue figured out.

For the example above, if a task had multiple requirements, your view would look something like the following for the requirements:

<% for requirement in @project.task.requirements %>
    <% fields_for "project[task_attributes][requirement_attributes]", requirement do |requirement_form| %>
      <p>
        Requirement: <%= requirement_form.text_field :name %>
      </p>
    <% end %>
  <% end %>

Then in the task model:

def requirement_attributes=(requirement_attributes)
    requirement_attributes.each do |attributes|
      self.requirements.build(attributes)
    end
  end

This seems to work.

Avatar

Cancel that. It works now with code from this page '$(this).up('something').remove()'

Tnx anyway for these casts and code snippets :)

Avatar

Hi Ryan,

I want to thank you a lot for your railscasts. They helped me quick start with Rails.

Regarding this episode, I have problem with remove js call in IE6 (FF works just fine). Actually, I think insert_html makes problem because even alert('something') doesn't work when it is put instead of 'this.up('something').remove()'. Error that IE 'raises' is 'Object doesn't support this property or method'.

Do you have any idea how to solve this problem please?

Avatar

Hi there Ryan!

Long time listener first time caller! First things first, you're awesome!

OK second thing... something I've been wondering for a while is whether it's possible to extend scopes from somewhere else (e.g. a controller).

for example, in this episode you have:

scope_out :incomplete, :conditions => ['complete=?', false]

Sometimes I might want to add extra conditions when using this:

Task.find_incomplete(:all, :conditions => "rank = 'urgent'")

Do you know if there is a way to do this? maybe if you pass the conditions as a hash? (is this only available in edge rails?)

Avatar

When, and only when, I add the JS link to ADD the partial i get this error from my partial:
`@raid[attendee_attributes]' is not allowed as an instance variable name

Avatar

Ryan, in episode #13, "Dangers of Model in Session" you mention that it is a good practice to avoid storing model data within a session, or at least minimizing the amount of model data you store in a session.

In looking through the source code for the restful_authentication plugin, it appears as though that plugin is storing information in a @current_user variable and in a session variable (assuming your model is called user).

Is the approach being used in that plugin to store the user model in the session, I was just a little confused and thought you might be able to chime in on the topic.

Avatar

Another great screencast, thanks Ryan!

I've been using scope_out for some time, but unfortunately every now and then, I encountered problems especially when it comes to pagination. Some time ago I wrote up a summary in my blog: http://zargony.com/2007/07/21/paginating-special-queries/

Recently I started to use the HasFinder plugin instead of scope_out. HasFinder works almost like scope_out, but it additionally gives you an easy way to arbitrarily combine scopes, like @project.tasks.incomplete.important (Task has finders :incomplete and :important). Plus it works out of the box with caching and pagination. I posted a quick summary at http://zargony.com/2007/10/20/paginating-special-queries-with-hasfinder-and-will_paginate/

HasFinder can be found at http://www.pivotalblabs.com/articles/2007/09/02/hasfinder-its-now-easier-than-ever-to-create-complex-re-usable-sql-queries

Avatar

I like how you are still actively releasing new podcasts. Most of the other "programming" podcasts I came accross either have irregular updates or just stop updating all together after a relatively short period of time. July was your most active month; if you could repeat that I wouldn't complain!
anyway, fantastic podcasts. Keep up the good work.

Avatar

+1 for another screencast discussing error messages and validations in greater detail.

Avatar

I think there is a problem with the video file. I can't open it with VLC Player on PC. Could you please check it out? Thank your.

Avatar

Ted,

You can see how to do that on scope_out's home page

http://code.google.com/p/scope-out-rails/

Avatar

Great stuff, as usual. If Task had two scope outs, say "incomplete" and "ordered by name", how might you combine them when needed? I hope there's a part 2 to scope_out :-) Thanks.

Avatar

Woohooo! First Comment!

I'm special :)

Avatar

what about adding task has many sub_tasks
In field_for what name I have to use
"project[task_attributes][][sub_task_attributes][]" is not work.

Avatar

What is the projects_path variable? I don't see any mention of how it gets set.

Avatar

More on complex forms and validation is very welcome. I'm trying to do the reverse of your relationship here. I'm trying to create a User that belongs_to a group. I've discovered how to do that with "build_group", but I need validate the created group before saving the user, if the user is creating a new group. Otherwise, I just want to validates_presence_of the group selected in a drop down. The whole validation system, with callbacks and conditionals, is pretty hard to get a good overview handle on.

I love your work. Thank you!

Avatar

For moving error messages from failed task validations up to the project error messages, I added this "after_validations" method to Project:

http://pastie.caboo.se/109132

Avatar

[quote]
after_update :save_tasks

  def save_tasks
    tasks.each do |t|
      if t.should_destroy?
        t.destroy
      else
        t.save(false)
      end
    end
  end
[/quote]

when @project.save, it automatically save the @project.tasks. Then Rails calling the callback save_tasks ?
Would the same task do update twice ?

Avatar

@Gilles, for the date_select, use

:index=>''

rather than

:index=>nil

Avatar

I have a similar issue to @Ryan Lundie, creating the same effect with a many-to-many relationship.

I just viewed the tutorial for the first time tonight and am going to tackle it... hopefully I can adapt this tutorial to my needs.

In any case, these tutorials are great. Thanks so much for putting your time into creating these for everyone.

Mark

Avatar

I think that we could simplify this example a lot when not worrying weather task is new or updated.
On each update we could first delete all existing tasks and then add all submitted:

def task_attributes=(task_attributes)
  tasks.clear
  task_attributes.each do |attributes|
    tasks.build(attributes)
  end
end

This way we could remove all marking of new and deleted records and save_tasks method.
We should probably had to mark tasks association as :dependent => :delete_all and add transaction in controller so we don't lose tasks if some validation fails.

Avatar

I'm sorry, I meant to post this on episode 33 making a plugin. In that episode, you ended with a validate method in the task.rb file and I was wondering if it were possible to include that in the plugin?

Avatar

I noticed that using the create_category method doesn't run the validations in the related model "category.rb" Is there a good way around this or do we need to redo our validation checks in the method like LoRiBoX's comment above. I'm sure there is a DRYer way to do it but I'm not sure how.

Avatar

This might sound like stupid question. I recently started learning php with sql. This looks like php coding but am not sure. It maybe little advance for me or maybe am just been stupid and there is previous tutorials.... I looked at #1 because I thouth it would be the easiest to get my head round. I kinda understand what is going on in this tutorial... but I am not sure where I would apply such a method? Thanks Ste

Avatar

Just to close out the transaction discussion, this from the Rails doc:

Save and destroy are automatically wrapped in a transaction.

Both Base#save and Base#destroy come wrapped in a transaction that ensures that whatever you do in validations or callbacks will happen under the protected cover of a transaction. So you can use validations to check for values that the transaction depend on or you can raise exceptions in the callbacks to rollback.

http://caboo.se/doc/classes/ActiveRecord/Transactions/ClassMethods.html

Avatar

@john, if the project has no tasks then it is treated as an empty array so neither of the issues you mentioned should be a problem. But I haven't tested it extensively, does it not work?

@Gilles, I'm pretty sure you can adapt this to work with HABTM. One thing you'll have to do is decide how the removal process will work. Does it just remove the join or the end model? Everything else is very similar.

@Skyblaze, no PDF, but I'll be writing a few tutorials on railsforum.com in the near future showing this technique with possible additions.

Avatar

Hey,

I really need to get this thing to work wiht ajax, i need a link to remote to update a specific id and I can't get any info on how to do that...plus I am not very good with rails...can someone help out with this?

Avatar

Anyway i still think that short particular arguments like this are better explained in mini-pdf. Will you release them in the future?