questions about inheritance in Rails

2 views
Skip to first unread message

Tim Ferrell

unread,
Jun 6, 2007, 10:29:11 AM6/6/07
to rubyonra...@googlegroups.com

I am in the process of subclassing some things in a current Rails
project and would like some feedback on how I'm approaching it... what I
have works but I'm not sure if there is a better way to approach this.
:-)

I am currently subclassing controllers like so:

class LookupsController < ApplicationController
# GET /lookups
def index
end

#-----------------------------------------------------------------
# the rest of these methods are called from subclassed controllers
#-----------------------------------------------------------------

# GET /{controller_name}
# GET /{controller_name}.xml
def index_list
render 'lookups/index' and return if controller_name == 'lookups'
eval('@' + controller_name + ' = ' + model_name + '.find(:all)')
respond_to do |format|
format.html { render 'lookups/list' }
format.xml { render :xml => eval('@' + controller_name +
'.to_xml') }
end
end

# ... and so on ...
end

class StatesController < LookupsController
def index
index_list
end
end

and the shared view template looks like this;


<h1><%= pretty_controller_name %></h1>
<table>
<thead>
<tr>
<td id="col_actions">Actions</td>
<td id="col_name">Name</td>
</tr>
</thead>
<tbody>
<% for item in eval('@' + controller_name) %>
<tr class="<%= cycle("even","odd") %>">
<td>
<span class="itemActions">
&nbsp;
<%= link_to(image_tag('item_delete.gif'),
eval(model_name + '_path(:id => item)'),
:confirm => 'Are you sure?',
:method => :delete,
:class => 'image_link') %>
<%= link_to(image_tag('item_edit.gif'),
eval('edit_' + model_name + '_path(:id => item)'),
:class => 'image_link') %>
</span>
</td>
<td class="itemName">
<%= item.name %> <span class="itemCount">(<%=
pluralize(item.jobs.count, "job") %>)</span>
</td>
</tr>
<% end %>
</tbody>
</table>
<br />
<%= submit_tag "Add a " + pretty_model_name, {:type => 'button',
:onClick=>"parent.location='" + eval('new_' + model_name + '_path') +
"'" } %>

and a helper like so:

module LookupsHelper
def controller_name
controller.controller_name
end
def model_name
controller.controller_name.singularize
end
def pretty_model_name
model_name.gsub('_', ' ').capitalize_all
end
def pretty_controller_name
controller_name.gsub('_', ' ').capitalize_all
end
end

My main question revolves around the liberal use of eval() ... is there
a better way? Am I making this harder than it should be?

Thanks for any feedback...

Cheers,
Tim

--
Posted via http://www.ruby-forum.com/.

dbl...@wobblini.net

unread,
Jun 6, 2007, 10:39:19 AM6/6/07
to rubyonra...@googlegroups.com
Hi --

On Wed, 6 Jun 2007, Tim Ferrell wrote:

>
>
> I am in the process of subclassing some things in a current Rails
> project and would like some feedback on how I'm approaching it... what I
> have works but I'm not sure if there is a better way to approach this.
> :-)
>
> I am currently subclassing controllers like so:
>
> class LookupsController < ApplicationController
> # GET /lookups
> def index
> end
>
> #-----------------------------------------------------------------
> # the rest of these methods are called from subclassed controllers
> #-----------------------------------------------------------------
>
> # GET /{controller_name}
> # GET /{controller_name}.xml
> def index_list
> render 'lookups/index' and return if controller_name == 'lookups'
> eval('@' + controller_name + ' = ' + model_name + '.find(:all)')
> respond_to do |format|
> format.html { render 'lookups/list' }
> format.xml { render :xml => eval('@' + controller_name +
> '.to_xml') }
> end
> end

This is all sort of at first glance, so I could well be overlooking
some pitfalls, but why don't you just say @items or something instead
of all the eval'ing? Also, instead of model_name, you could have your
helper method return a model class. That way, you could do:

@items = model.find(:all)

> # ... and so on ...
> end
>
> class StatesController < LookupsController
> def index
> index_list
> end
> end
>
> and the shared view template looks like this;
>
>
> <h1><%= pretty_controller_name %></h1>
> <table>
> <thead>
> <tr>
> <td id="col_actions">Actions</td>
> <td id="col_name">Name</td>
> </tr>
> </thead>
> <tbody>
> <% for item in eval('@' + controller_name) %>
> <tr class="<%= cycle("even","odd") %>">
> <td>
> <span class="itemActions">
> &nbsp;
> <%= link_to(image_tag('item_delete.gif'),
> eval(model_name + '_path(:id => item)'),

At the very least I would use send there:

send("#{model_name}_path", :id => item)

But it's nicer if you can encapsulated that kind of calculation in the
controller or a helper method.

I'll leave it at that, pending feedback on what I've missed :-)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

Tim Ferrell

unread,
Jun 6, 2007, 10:54:05 AM6/6/07
to rubyonra...@googlegroups.com
David wrote:
>
> This is all sort of at first glance, so I could well be overlooking
> some pitfalls, but why don't you just say @items or something instead
> of all the eval'ing? Also, instead of model_name, you could have your
> helper method return a model class. That way, you could do:
>
> @items = model.find(:all)
>

Thanks... good point. :-) I was so focused on translating the existing
code that I missed that.

>
> At the very least I would use send there:
>
> send("#{model_name}_path", :id => item)
>
> But it's nicer if you can encapsulated that kind of calculation in the
> controller or a helper method.
>

In other words, wrap the route method invocation with a helper method to
simplify the view code?

One other question comes to mind... in the view I am creating a
button...

<%= submit_tag "Add a " + pretty_model_name, {:type => 'button',
:onClick=>"parent.location='" + eval('new_' + model_name + '_path') +
"'" } %>

Is there a cleaner way to do this besides building the onClick
javascript?

> I'll leave it at that, pending feedback on what I've missed :-)

Thanks much for the feedback!

dbl...@wobblini.net

unread,
Jun 6, 2007, 10:58:18 AM6/6/07
to rubyonra...@googlegroups.com
Hi --

On Wed, 6 Jun 2007, Tim Ferrell wrote:

>
> David wrote:
>>
>> This is all sort of at first glance, so I could well be overlooking
>> some pitfalls, but why don't you just say @items or something instead
>> of all the eval'ing? Also, instead of model_name, you could have your
>> helper method return a model class. That way, you could do:
>>
>> @items = model.find(:all)
>>
>
> Thanks... good point. :-) I was so focused on translating the existing
> code that I missed that.
>
>>
>> At the very least I would use send there:
>>
>> send("#{model_name}_path", :id => item)
>>
>> But it's nicer if you can encapsulated that kind of calculation in the
>> controller or a helper method.
>>
>
> In other words, wrap the route method invocation with a helper method to
> simplify the view code?

Yes -- something like:

def model_path(*args)
send("#{model_name}_path", *args)
end

at which point you could do:

<%= link to "Click here", model_path :id => item %>

There may be yet further ways to simplify it all but initially at
least I'd go for pushing all the low-level-ish stuff out of the views
and see what happens.

(Punting on the JS question... :-)

Reply all
Reply to author
Forward
0 new messages