Topic: What's the right Rails idiom for dealing with contained objects

I've been working on the administration panel of my application and I've gone through about 3-4 different approaches to controller organization/url space.  (This is related to by earlier thread on this forum titled Control Panels and large number of contained models).

In my case, the user selects/creates a competition and then starts to configure it.  This includes establishing a list of levels, styles, costs, and events.  The selected competition object (or its id) must remain available through a long series of operations.  Now, in the non-admin area of the site I basically need some human readable form of the competition name in the URL (often suitably abbreviated).  I'm using to_param to handle this and that works well.  The non-admin area, however is rather linear/wizard-like and as a result the controller/views are more complex and not as model focused as the admin area.

So I was going to initially piggy-back on my to_param in the admin section as well, so I would have urls like
domain/competitions/Human_Name/admin/<controller>/<action>/<id>
This was "working" and I like the format, however, it seems to be a minor disaster when it comes to route generation and most testing tools expectations.  All url generating functions need to have the :short_name=>@competition.short_name appended to the parameter list for it to inject it into the URL; and its mighty un-DRY.

Now I could stick the competition_id into the session and avoid this, but it doesn't get rid of the problem as there are "landing" pages where I'll have to use the human readable URL, but it would solve my current problem.

Is there an easy way to handle this?  There's a ton of functions that would need to be overridden in an intermediate class between my Controllers and ActionController::Base and not all of them are actually part of AC::Base -- named routes, form_tag helpers, etc.

Its somewhat similar to the AR::Base's with_scope... is there something similar for AC::Base?

My RoR journey  -- thoughts on learning RoR and lessons learned in applying TDD and agile practices.

Re: What's the right Rails idiom for dealing with contained objects

Just a crazy idea, and probably not a very good one. Have you tried overriding url_for in the controller's helper module to always pass along the competition's short name? I believe all of the helper functions use url_for (form_tag, link_to, etc.) when needing a URL. In a sense that almost behaves like with_scope.

As I said, just a crazy idea. I have no clue if this is a good thing to do or if it even solves your problem.

Railscasts - Free Ruby on Rails Screencasts

Re: What's the right Rails idiom for dealing with contained objects

I'm playing with this right now, but I'm not entirely sure what I should be doing...

This is what I'm trying, but its giving rails errors everywhere.

  protected
  def url_for(options={}, *params)
    options[:short_name]=@competition.short_name
    super.url_for options, params
  end

You were right in that all the other URL rewriting functions seem to rely on this function.  However they seem to use it in weird ways -- for instance redirect_to seems to result in a call to url_for with a single string argument (the complete fully assembled (and correct ) URL.  This triggers a NoMethodError: undefined method for url_for or "http://.....":String.

Calls to link_to generate the same error, but don't generate the correct URL (ie it appends (?id=3) instead of the normal rails "/3" convention.

Calls to start_form_tag are similar to the redirect_to error.

The docs talk about how redirect_to can be called with a string argument, but I don't see what generates a call to url_for with a string argument.

Did you have another idea in mind for how to override this?

My RoR journey  -- thoughts on learning RoR and lessons learned in applying TDD and agile practices.

Re: What's the right Rails idiom for dealing with contained objects

Try placing this in the controller (not the helper).

  protected
  def url_for(options = {}, *params)
    options[:short_name] = @competition.short_name if options.is_a?(Hash) && !@competition.nil?
    super
  end

That seemed to work for me. Obviously it will only work if the input is a hash (url_for also alllows strings and symbols). It's an ugly hack, but hey, I guess if it gets the job done...

Railscasts - Free Ruby on Rails Screencasts

Re: What's the right Rails idiom for dealing with contained objects

Interesting, I'll give that a try when I get home.  Teach me to trust the documentation... none of them mentioned the calling it with a string or symbol was legimate.  Though I should have expected such as all of the methods that call url_for document the other syntaxes. (And got to remember that "super" by itself is sufficient to call the overridden method.)

My RoR journey  -- thoughts on learning RoR and lessons learned in applying TDD and agile practices.