RailsCasts Pro episodes are now free!

Learn more or hide this

Recent Comments

Avatar

Ryan, excellent Railscast thank you.

How are you populating the form with sample questions simply using a keyboard shortcut?

Avatar

Turns out that child_index is *not* the id. It is just an index and doesn't really mean anything except that it has to be unique.

Rails associates the id for a given nested record with a particular index by inserting a hidden field like this into the form:

<input type="hidden" value="514" name="contact[emails_attributes][7][id]" id="contact_emails_attributes_7_id">

Where in this case 7 is just an index (normally counts up from 0-(n in collection -1) and 514 is the id.

It doesn't really matter if you do a normal submit but if you want an ajax form that submits on any change, you need to get the id back from the server and add that hidden input or subsequent ajax submits will result in duplicates being created.

Just thought I'd share because it took me a while to figure this out and most references on the web also incorrectly state that it is the id.

Avatar

This was great! Emailing via forms has long been a mystery to me. So simple even -I- can do it

Avatar

After hours of "not recognized by the 'identify' command" I can recommend any windows-user to install imagemagick into a path w/o whitespaces. still you'll need to set the command_path like:

Paperclip.options[:command_path] = "C:/ImageMagick-6.6.2-Q16/"

(ve put it into the development.rb). good luck ;-)

Avatar

Obviously this is an old post, but if anyone is playing with tree based navigation, try this:

http://github.com/ktec/elements

The model uses the "ancestry" to provide a tree structure, and STI to provide different elements of the site. I'm working on getting the wonderful jquery jstree fully functioning, but all the code is there if anyone wants...

Avatar

Thanks for the useful tip

Avatar

Redirect from polymorphic CREATE and DELETE action are here http://gist.github.com/440723

Avatar

Ryan, it might be interesing to modify your example

mailing.send_later(:deliver)

is deprecated. It looks like you now have to use

mailing.delay.deliver

Also for those who asked how to know when the job is finished one solution is to "do something" (in my case, call *again* the delay to restart again) at the end of the delayed method.

Avatar

Hi Ryan , many thanks for this.

I get it for simple model. But I can not figure out how to do with HABTM model.

thanks again

Avatar

If you get error: There's an error with this transaction. Please enter a complete billing address, you will need to accept the billing agreement on your paypal account (one of the steps in the setup process)

Avatar

Thank you! Thank you! Thank you! Exactly what I needed when I needed it!

+1 vote for a refactored controller, if you want to bang out a quickie. ;) Also, I think it might be a good idea to show storing the params in the DB and using the update action rather than sessions when you do the refactored controller.

Thanks again! You're the best!

Avatar

My bad, actually you only need to use the rails new [APP_NAME] style when you're inside an existing rails app directory structure. Otherwise the old style without "new" works.

Avatar

For Rails 3 beta4 you need to use command

    rails new topscore

to create a new rails project.

Avatar

Wow Ryan, that's a lot of spam you've managed to harvest. :-) Perhaps a CAPTCHA of some sort might be in order?

I hope my clicking those links for you at least puts them in a queue so you can "delete all".

Avatar

Ryan,

I was going throught this post
http://blog.envylabs.com/2009/08/the-rails-state-machine/

ruby has state machine built in the models,

Any particular reason you didn't use it, also if you can cover it in later screencasts.

Avatar

This is excellent as always! Thank you so much. One thing though: Doing this seems to break my "rake routes" with an "uninitialized constant ActionView". I'm still pretty green with rails so I don't know the answer to this myself or really where to look yet. Do you have a fix for this? (For right now I just comment my block out and run rake routes)

Thanks so much!

Avatar

Just reviewed #216, and found this one. You are unbelievable. Thanks a lot.

Avatar

+1 for validations, it's very troublesome problem.... not easy

Avatar

I have the same problem as Rolando. I made the username as unique but it displayed error on submitting the form. Anyway to handle this?

Avatar

The link above with grouping by year then month isn't formatted properly. Maybe pastie has changed their parsing since it was created.

Go to http://pastie.org/1003477 instead.

Avatar

I've got this working and I'm happy with it, except for one thing: how do I ensure that any html class specifications are propogated each time a new entry row is created?

For example, in my _field partial, I have a textfield that should be of a certain class:

<%= f.text_field :rent ,:class=>'auto' %>

Unfortunately, the addition of more of these fields with link_to_add does not seem to propagate the html class info!

Avatar

Ryan,

How did you get bundler to work with rake? I'm running bundle 0.9.26 and rake 0.8.7, but rake is erroring out when I do the first db:migrate. I've read on some other posts that you need to 'gem install' separately not using 'bundle', but you're doing it. What is your trick?

Avatar

I generally do something similar, but prefer to wrap all the workflow logic into separate module/classes that just check the state of one or more model objects.

For example you might have an OrderWorkflow class which has a #steps method that returns an array of FirstStep/SecondStep etc. objects. Each step object implements a complete? method & the OrderWorkflow#current_step simply returns the first object that is not complete.

One advantage of that is that you can take advantage of rail's partial rendering on objects to provide different views for each step.

Avatar

Great screencast per usual. I've started using my own templates for scaffolding and found it makes life just that much simpler. I was wondering if anyone has tried changing the rails new generator so that each new project creates the same lib/templates directory. Figure this kinda makes your nifty-generators a little outdated.
Cheers.

Avatar

How do I test this with webrat? The checkboxes can't be located with CSS or Xpath. I'm tearing my hair out. I didn't have much to start with.

An example would be awesome.

Thanks!

Avatar

session? very bad way, one textarea field that user can put a lot of text and cookie session broken.

hidden fields is more safe way (but it not work like and session if upload need)

(params[:order]||{}).each_pair do |k,v|
hidden_field_tag "order[#{k}]", v
end

at bottom or top of form, I'm not remeber params parsing order

Avatar

@Michael

No problem! Glad to help.

Avatar

I try it on rails 3 beta4 accoring to your example.But it fail on rake task mode and pass on "ruby test.rb" mode. Same rake task pass on Rails 2.3.5.
Ruby version is 1.8.7.OS is ubuntu 9.04.

May i seek your help to solve it ?

Avatar

I try it on rails 4 beta accoring to your example.But it fail on rake task mode and pass on "ruby test.rb" mode. Same rake task pass on Rails 2.3.5.
Ruby version is 1.8.7.OS is ubuntu 9.04.

May i seek your help to solve it ?

Avatar

Can anyone point me in the direction of using Paperclip for file attachments that are not images? I can attach, but get errors when trying to retrieve the files. I'm pretty sure it's due to the :url path I have in my model, but I'd like a tutorial for non-image attachments so I can follow from scratch... thanks in advance.

Avatar

One more note.

The edge documents here:
http://edgeguides.rubyonrails.org/active_record_querying.html

Say:
4.2 Specifying Conditions on Eager Loaded Associations

Even though Active Record lets you specify conditions on the eager loaded associations just like joins, the recommended way is to use joins instead.

---

But they don't say how to eager load associations using joins.

Avatar

Ok, I now understand why it's using LEFT JOINS. (It has to in case the first model does not appear in the second's table).

Here is the real problem as I see it:

When I place a where clause on an included model, AR stops fetching each model in its own query and combines everything into a big LEFT JOIN monstrosity.

While this works, it is very non-performant when several models are included as I get back many many rows that all need to be aggregated by the ORM. This also requires more network IO.

I've created this Gist to demonstrate what's happening:
http://gist.github.com/431943

I'll send a pizza to anyone who can help me with this.

Avatar

In find_commentable, it might be better to use:

$1.pluralize.classify.constantize.find(value)
or
$1.titleize.constantize.find(value)

I ran into problems when classify was called on a model like 'business', yielding 'busines' and throwing fun little errors.

Not everyone needs it but it's a caveat that is annoying at best...

As always, thanks Ryan!

Avatar

Why does .includes not behave like .joins?

Phrase.joins(
  :feed_entry_phrase_correlations).merge(
  FeedEntryPhraseCorrelation.since(
  10.minutes.ago)).all

Generates this sql:

SELECT
  `phrases`.*
FROM
  `phrases`
  INNER JOIN `feed_entry_phrase_correlations` ON `feed_entry_phrase_correlations`.`phrase_id` = `phrases`.`id`
WHERE
  (feed_entry_phrase_correlations.created_at > '2010-06-09 16:23:42')

Whereas using .includes:
Phrase.includes(
  :feed_entry_phrase_correlations).merge(
  FeedEntryPhraseCorrelation.since(
  10.minutes.ago)).all

Generates this sql:
SELECT
  `phrases`.`id` AS t0_r0,
  `phrases`.`phrase` AS t0_r1,
  `phrases`.`created_at` AS t0_r2,
  `phrases`.`updated_at` AS t0_r3,
  `feed_entry_phrase_correlations`.`id` AS t1_r0,
  `feed_entry_phrase_correlations`.`feed_entry_id` AS t1_r1,
  `feed_entry_phrase_correlations`.`phrase_id` AS t1_r2,
  `feed_entry_phrase_correlations`.`count` AS t1_r3,
  `feed_entry_phrase_correlations`.`created_at` AS t1_r4,
  `feed_entry_phrase_correlations`.`updated_at` AS t1_r5

FROM
  `phrases` LEFT OUTER JOIN `feed_entry_phrase_correlations` ON `feed_entry_phrase_correlations`.`phrase_id` = `phrases`.`id` WHERE (feed_entry_phrase_correlations.created_at > '2010-06-09 16:23:42')

Avatar

I'm trying to implement this on an edit page (rather than a new page) and in my application I have Buildings and Rooms instead of Countries and States, but the relationship is basically the same.

It is not working for me. Regardless of which Building (country) I select, the list of Rooms (states) does not change. I have no idea what the problem is.

Avatar

Thanks Ryan for the great code, it is just what I needed.

I have this all set up and working well in my project. My only problem is that in one of my nested forms I have a f.select field - this works perfectly in the new.html.erb but I can't get it to show the selected item per the activerecord when I edit it (although the select list shows all the options, so it is working) thanks

Avatar

I'm getting an error when using deep_merge! it is assuming that the sessions hash is nil for some reason. I'm getting this error:

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.deep_merge!

The code is like this:

  def new
    session[:user_params] ||= {}
    @user = User.new
  end
 
  def create
    session[:user_params].deep_merge!(params[:user]) if params[:user]
    logout_keeping_session!
    @user = User.new(session[:user_params])
    @user.current_step = session[:user_step]
    if params[:back_pressed]
      @user.previous_step
    else
    @user.next_step
  end
    session[:user_step] = @user.current_step
    render "new"
end

Can anyone help?

Avatar

I implemented this, and all works fine...except my select list is not ordered alphabetically. Any ideas?

Thanks!

Avatar

Do you really need self in self.current_step? Would this not work if you simply assign to current_step?

Sorry if I am missing something very basic.

Avatar

Hi Ryan,

Great episode. For a production app, I suggest more investigation of storing the partially completed form in the model.

The issue is that "abandonment" is common with multi-step forms. If the partial information is stored, analysis can be done to discover when and how often the form is being abandoned.

Re @dkjess and funnel analysis--you can usually call your analysis system explicitly via javascript and tell it which funnel step the page is currently showing.

Avatar

@71. Regnum

Thanks for the file renaming tip. Also I found that you can't have spaces in the name of your file or it cuts off everything after the first space. I just replaced them with underscores thru a helper method.

Avatar

Ryan,

you have NO idea how long I've been waiting for an explanation for how to do this. I don't think I would've ever figured it out on my own. Thank you so much!

Avatar

@RaynB this is a nice way of doing a multistep form in rails, but your method is missing unique urls for each step. The urls are needed in order to get funnel tracking working correctly.

I know that this is not Rails specific, but would be required for a real world app.

Anyway, keep the Railscasts coming :-)

Avatar

Hello Ryan,

Its good to use workflow + validatable for such things. Much cleaner.

http://github.com/geekq/workflow

Avatar

Re: using hidden form fields as an alternative to the session:

To avoid duplicating the list of fields, I've been playing with passing *one* hidden field, compressed_order_params, containing a gzipped yaml dump of any previous parameters.

So far, I'm liking it, but these are early days. :-)

ActiveSupport provides good help. Compressing the parameters looks something like the following, with decompressing pretty much the mirror image:

ActiveSupport::Base64.encode64(
  ActiveSupport::Gzip.compress(
    hash.to_yaml
  )
)

Avatar

When I started learning RoR this was the first project I had but I went a different route that took way longer than it should have and way to much code. This is completely simplified compared to what I have. I'll have to implement this method of the multi-step form. Thanks for doing this. Looking forward to the refactoring.

Avatar

Would we not have problems using the session, if the user opened a new window and wanted to edit two products at the same time?

Instead of storing the variables in the session, we could equally store them in hidden fields. We could create another model object called old_product, and then store its properties in hidden fields in the form.

Avatar

Ryan, I got a problem. I configure devise for authenticating with a username. But I realize that the username is not unique and when you register a new user it lets you duplicate.

Any idea?