Controllers in folders and helper scope in Rails >1.0

Hi,

Here’s my problem. I tried to google it, read the release-docs and
haven’t found anything similar.
My application uses folders to store controllers, as described in the
Rails book. I need to have same-named controllers for admin and for
users, so it looks like this:

/app/controllers/admin/project_controller.rb
/app/controllers/admin/…
/app/controllers/project_controller.rb
/app/controllers/…

The controller-classes are properly scoped like this:

/app/controllers/admin/project_controller.rb has:

	class Admin::ProjectController < ApplicationController
	  layout  "admin"
	  def index
		...
	  end

/app/controllers/project_controller.rb has:

	class ProjectController < ApplicationController
	  layout  "user"
	  def index
		...
	  end

Those controllers make use of helpers, and again, there are global
ones (used by both by users and admins), and special ones for admins.
So it looks like this:

/app/helpers/admin/project_helper.rb
/app/helpers/admin/…
/app/helpers/project_helper.rb
/app/helpers/…

The admin helper contains properly scoped content:

module Admin::ProjectHelper
...
end

and normal helper has also:

module ProjectHelper
...
end

It is important, that admin-scope controllers are also accessing and
using constants and classes defined in user-scope helpers. This
worked fine in 0.14.x and in 1.0 versions of Rails. Now I’m trying to
move to 1.1.1 through Locomotive bundle or 1.1.2 through normal means
(sudo gem update rails, …, etc) and this behavour breaks.

The original working code in the admin-controller is like this:

class Admin::ProjectController < ApplicationController
  layout  "admin"
  def index
    @project_display_options =

ProjectHelper::ProjectDisplayOptions.new(params, session)

and it accessed ProjectDisplayOptions class from the user-scope helper:

module ProjectHelper
  class ProjectDisplayOptions
    attr_accessor :project
    ...

Now, in Rails 1.1.x, my application breaks as if the user-helper
scope was unavailable for admin-scope controller:

NameError in Admin/projectController#index
uninitialized constant ProjectDisplayOptions
...
#{RAILS_ROOT}/app/controllers/admin/project_controller.rb:6:in `index'

line 6 leads to:
@project_display_options = ProjectHelper::ProjectDisplayOptions.new
(params, session)

The browser response also contains this:
This error occured while loading the following files:
admin/project_helper/project_display_options.rb

which seems to come from the new dynamic mechanism trying to load an
unknown class from a same-named file. But I’m not sure is this is
really what’s supposed to happen.
I can fix the problem by copying-pasting the problematic class from
user-scope helper to the admin-scope-helper, but this is not DRY, of
course. And what happened, that the behaviour of Rails has changes in
1.1? I can’t find anything relevant in the release-notes.
My application is a small internal tool, but certainly is was running
for the last six months on 0.13, 0.14 and on 1.0 versions of Rails.

Any help? TIA.

RafaÅ? Komorowski
[email protected]
GG: 4083718
http://homepage.mac.com/komor/iblog/

On 23/04/2006, at 20:49, RafaÅ? Komorowski wrote:

My application uses folders to store controllers, as described in
the Rails book.
[cut]
/app/controllers/admin/project_controller.rb
/app/controllers/admin/…
/app/controllers/project_controller.rb
/app/controllers/…
[cut]
/app/helpers/admin/project_helper.rb
/app/helpers/admin/…
/app/helpers/project_helper.rb
/app/helpers/…

[cut]

Now, in Rails 1.1.x, my application breaks as if the user-helper
scope was unavailable for admin-scope controller:

I solved my problem by changing this:

 @project_display_options =

ProjectHelper::ProjectDisplayOptions.new(params, session)

to this:

 @project_display_options

= ::ProjectHelper::ProjectDisplayOptions.new(params, session)

in the admin controller code.

Seems reasonable, but still I’m pretty sure something has changed in
the Rails 1.1, because I’ve done a test:

  • make a fresh empty app,
  • generate controllers (with admin in subfolder),
  • fill-in a placeholder code in controllers, helpers and views.
  • see if it works to access user-scope helper in admin-scope controller.

The interesting thing happens then in Rails 1.1.x: if my initial
request is the admin-scope one (http://localhost:3000/admin/project)
then application fails, as if Rails couldn’t see the user-scope
helper yet. But after issuing user-scope request (http://localhost:
3000/project) the admin controller runs okay, as if Rails already
“saw” the helper and loaded it properly. I’m wondering if this is the
way Rails works?

All those tests were done in Rails 1.1.2 installed by normal means
(Dan Benjamin
ruby_rails_lighttpd_mysql_tiger) on Mac OS X 10.4.6, and also through
Locomotive with 1.1.1 bundle, and they fail in the described way.
But when using Locomotive with 1.0 bundle the app succeeds always,
that is: admin-scope controller always sees user-scope helper, and
my problematic application works fine, and it did for the last couple
of months.

So my suspection here is: Rails 1.1 is “lazy” in loading helpers, and
Rails 1.0 is not. Or it is my fault and I’ve always should prefix my
call with the :: in the admin-scope code?
If all my observations are not a crap and anybody is interested in
investigating it, I can prepare a step-by-step instruction how to
replicate a problem, with a test code (simple placeholder code, that
is).

RafaÅ? Komorowski
[email protected]
GG: 4083718
http://homepage.mac.com/komor/iblog/

Everybody seems to ignore my thread :slight_smile: so I will throw one last
question: is it wrong to call objects/methods defined in helper from
the controller code?

RafaÅ? Komorowski
[email protected]
GG: 4083718
http://homepage.mac.com/komor/iblog/

On 26/04/2006, at 10:28, Chris T wrote:

Just to show it’s not being ignored (and speaking as a not-
completely-got-my-head-around-OO-yet-ex-PHPer),

Thanks Chris :smiley:

I think that helpers are supposed to be called from views. From
the API:

Yes, I’ve read this in the Rails book, too. But I have some data-
structures that seem to be both model-related, and view-related. Some
popup menus that are commonly built in the views, you know: project-
type, custom month-list or whatever. Should I just move them to the
model? Or to the controller, better yet.

RafaÅ? Komorowski
[email protected]
GG: 4083718
http://homepage.mac.com/komor/iblog/

RafaÅ? Komorowski wrote:


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Just to show it’s not being ignored (and speaking as a
not-completely-got-my-head-around-OO-yet-ex-PHPer), I think that
helpers are supposed to be called from views. From the API:

The template helpers serve to relieve the templates from including
the same inline code again and again. Itâ??s a set of standardized
methods for working with forms (FormHelper), dates (DateHelper),
texts (TextHelper), and Active Records (ActiveRecordHelper) thatâ??s
available to all templates by default.

Itâ??s also really easy to make your own helpers and itâ??s much
encouraged to keep the template files free from complicated logic.
Itâ??s even encouraged to bundle common compositions of methods from
other helpers (often the common helpers) as theyâ??re used by the
specific application.

I am struggling slightly (and I think it’s mainly me failing to 100% get
my head around the OO bit) where you then put methods used by controller
actions (in that controller, in application.rb, in /lib, or, I suspect,
to analyse things better so they better fit into MVC).

Not sure this helps…

On Apr 26, 2006, at 1:40 AM, RafaÅ? Komorowski wrote:

Yes, I’ve read this in the Rails book, too. But I have some data-
structures that seem to be both model-related, and view-related.
Some popup menus that are commonly built in the views, you know:
project-type, custom month-list or whatever. Should I just move
them to the model? Or to the controller, better yet.

Helpers are perfect for popups. I use helpers like this, but I have
them return just the data the built-in helper needs so the view is
very easy to understand and adjust:

def born_on_start_year
Time.now.years_ago(18).year
end

def born_on_end_year
Time.now.years_ago(100).year
end

def gender_select
[ [ ‘Male’, ‘M’],
[ ‘Female’,‘F’] ]
end

Gender:

<%= select ‘buyer’, ‘gender’, gender_select %>

Birthday:

<%= date_select ‘buyer’, ‘born_on’, :start_year =>
born_on_start_year, :end_year => born_on_end_year, :order =>
[:month,:day,:year] %>

If they’re in more than one view, put them in application_helper.rb

These particular helpers don’t need models, but here’s one that does:

def unit_select
Unit.find(:all,
:order => ‘seconds’).map {|u| [u.name, u.id]}
end

<%= select ‘seller’,‘unit_id’, get_units %>


– Tom M.