How-To Make a Rails Partial With Optional Locals (Parameters)

Sorry, this article has moved!

Explore posts in the same categories: DRY, partials

17 Comments on “How-To Make a Rails Partial With Optional Locals (Parameters)”

  1. […] Making a partial use optional parameters – Basically, set the parameter to nil inside the partial (e.g. title = nil unless defined?(title)) […]

  2. Hmm, “unless defined?” doesn’t work as I expect:

    $ ruby script/console
    Loading development environment.
    >> show_closed = true unless defined?(show_closed)
    => nil
    >> show_closed
    => nil

    $ ruby script/console
    Loading development environment.
    >> unless defined?(show_closed)
    >> show_closed = true
    >> end
    => true
    >> show_closed
    => true

  3. Doh! Actually, something is seriously wrong here. I’m using:

    unless defined?(show_closed)
    show_closed = true

    Sometimes I explicitly pass false. Sometimes I don’t pass anything. On the first load of the page, the default is applied. However, if I go to a page that explicitly passes false, and then I go back to the page that doesn’t pass anything, show_closed ends up being nil. Sure enough, show_closed goes back to being nil, but “defined?(show_closed)” is “local-variable”. Rails must be resetting all of these local variables to nil, but they’re still defined!

  4. Gregory Says:

    Actually that’s enough:

    title ||= nil

  5. Matt Says:

    Hi All,
    Thanks for the interest!

    Using ||= will only work if your value for the parameter can never be ‘false’… if you mean to send in false as a value for a parameter, using ||= will override it with the new value.

    Sorry you’re having trouble with it. It looks like script/console does something funky to values that aren’t defined. After playing around with it a bit myself, it doesn’t parse show_closed = true unless defined?(show_closed) as you’d expect at all.

    However, in ruby outside of script/console, like in partials, it performs fine. I’ve been using it successfully all over my application (opting to use it over ||=) quite well. Shannon, perhaps you can elaborate on what you mean by “going back and forth” between your pages?

  6. Adam Says:

    A quick warning: this technique will cause you sleepless nights if you use Markaby. At times, Markaby’s behind-the-scenes magic renders the locals hash inaccessible, so defined?(foo) will always return nil. However, Markaby stuffs the locals into its assigns hash, so you can access the locals as member variables. So…

    foo = nil unless defined?(foo)


    @foo = nil unless defined?(@foo)

    So far this appears to work for us.

  7. Matt Says:

    Hey… after much help in the comments, I’m switching to another method that seems to be used in core rails: param = default_value unless !local_assigns[:param].nil? — although it won’t work with HAML

  8. gmarik Says:

    i think it’s just enough

    title = local_assigns[:title]
    Isn’t it?

    Or just use local_assigns[:title] instead title – as it’ wont raise any errors

  9. Arron Says:

    I was having this problem too…

    It’s strange that there’s not an easy DRY solution for this in rails. I originally used your implementation, but then decided it was way too much writing for my taste (my fingers get tired/sore easily).

    I hacked up my own little plugin that does something similar (here: ).

    Simple, but works alright in my opinion.

  10. If you want this to work with HAML you should use _haml_local_assigns instead of local_assigns.

  11. roger pack Says:

    works like a charm. Thanks!

  12. An alternative approach to querying the local_assigns hash for each optional local would be to use a local hash called options, analogous to many of the methods in the Rails API. Then at the top of your partial just do:

    options ||= {}

    This approach of course makes setting the optional locals a little clumsier when invoking the partial. I like though that it makes it more clear when you are referencing an optional param in your partial. For clarity and to keep them separate from local variables, I would have prefered if Rails would have set all params passed to a partial in a hash called say partial.

  13. Red M@ Says:

    Thanks. That was very helpful!

    I totally agree that partials are analogous to methods. I am starting to learn to refactor reused peices of views into partials.

  14. Just wanted to say thanks. I google for this every time I need to remember the syntax/variable name!

  15. […] Making a partial use optional parameters – Basically, set the parameter to nil inside the partial (e.g. title = nil unless defined?(title)) […]

  16. scottwb Says:

    Nice writeup – I will have to try this out. Oddly, I have never had a problem with the defined? way that you started out with. I totally agreed with treating partials like methods – from day one on Rails I have been putting this kind of thing at the top of each partial:

    name = nil unless defined?(name)
    phone = nil unless defined?(phone)

    In fact, I often use this to define default value for the locals that are passed in, while letting an explicitly passed-in value of nil mean that the default value should be used, such as:

    name = ‘unknown’ unless (defined?(name) && name)

    That was all using RHTML…recently I started converting an existing rhtml-based project to haml and ran into a specific problem with this technique…but only when using a boolean value for a local. Consider that I want passing the local specifically to true or false to be preserved, but if you don’t specify it or pass in nil, then it should use a default value of true. So…I did this:

    show_name = true unless (defined?(show_name) && !show_name.nil?)

    This works like a charm when the partial is rhtml, but with haml, it seems that if I explicitly pass false for show_name to the partial, that it gets converted to nil. Doh!

    Not sure what path I am going to choose to address this in a large existing code base that relies on it…I might have to try out the _haml_local_assigns tactic mentioned above.

    For a simple code example that reproduces this problem, see my writeup on it at:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: