Different views for the same function

This question is more for future reference after I’ve made my website,
but one thing I’ve noticed was there was I had to make a lot of
functions on the controller, and different views for each one, each
with the same functionality. This is very anti-DRY, in my opinion.

So I was wondering, Is there some way to wrap all this up into a
single line of code in the controller, and ditto for the views?

I know a bit about partials, but is rather unsure about how to deal
with it in a form. How do I display a form partial, giving it
different variables each time?

For the controller, I have a few controllers extending off of user
(thought the names are different, basically they’re the moderators and
administrators). Since a user can edit itself, a mod can edit a user,
and an admin edit a mod, I have a lot of duplication in methods, just
so I can get different views off of each function. Since I’d rather
wrap it up in one view for the higher classes, is there some way to
wrap this unneeded extra functions using a bit of super() and
different validation methods? Must I put edit_self() method in the
Application controller?

Taro, if you;re talking about the very common functions for basic CRUD
operations on tables then yes, I think there are a few strategies to
keep DRY. I can see by reading around that the RESTful approach has
some pretty clear guidelines to help with this but I’m not there yet.

What I have found extremely helpful is a strategy of defining a parent
class from which I inherit for my classes (controllers) that do
concrete work.

So, lets call this controller Crud

class Crud < ActionController::base
bunch of stuff we’ll discuss below
end

and then my real controllers are

class Concrete < Crud

end

Now in the Crud controller I define some methods, specifically in my
case “show”, “new”, “edit” and “delete” (you can collapse these even
further if you wanted but for me this has been a reasonable balance
between being succint and being clear.

The next part is to take advantage of Rails consistency in naming. So
for a given controller we can deduce the model name. We know it will
have an id field as primary key and if we manage our routes
consistently then we know our parameters will be consistent. Then if
we agree to use a standard instance variable name for our form data we
can abstract the entire CRUD process. In my example, @row is what we
agree to always be the variable that holds data from the database.

Here’s an example for the “show” method:

def show
if !@row = crud_obj.find((params[:name]) then
redirect_to home_url
return
end
article_render_show
end

crud_obj is the model object related to our controller. It is defined
as below.

def crud_obj
return Object.const_get(class_name)
end

def class_name
return self.class.name.sub(/Controller/,"")
end

Once you have a way to abstract the name of the model class from the
controller class, you can pretty much abstract the entire crud
process.

I now have several controllers than have absolutely no code in them
whatsoever - they just inherit the methods from this parent class. To
create a new class I simply:

  1. Create a new class derived from Crud
  2. Create the views “show” and “edit”
  3. The logic will use “edit” for new and update functions, and “show”
    for the rest. You could easily decide to use only one view but I find
    they’re often different enough to warrant clear separation.

If you then create a customer form builder you can get a lot of basic
functionality built reliably very fast.

Cheers, --Kip

Hi Taro,

Taro wrote:

one thing I’ve noticed was there was I had to make a lot of
functions on the controller, and different views for each one,
each with the same functionality. This is very anti-DRY, in
my opinion.

So I was wondering, Is there some way to wrap all this up
into a single line of code in the controller,

Not sure if this is what you’re asking, but you can render whatever view
you
want from any controller action with :render => ‘action’. That will
render
the view for the action specified using whatever instance variables
you’ve
created in the action you’re in.

and ditto for the views?

I know a bit about partials, but is rather unsure about
how to deal with it in a form. How do I display a form
partial, giving it different variables each time?

:locals => {:var_in_form, @var_from_controller,
etc…}

HTH,
Bill

To Bill,
Sorry, I was in a rush. I’ll try to explain this a little more
thoroughly:

Basically, I have user classes set-up as ApplicationController >
UserController > ModeratorController > Admin Controller. As you can
see, Mods inherits user methods, and Admins inherit Mods methods. The
same goes for the Models; User > Moderator > Admin.
Right now, my edit methods goes as follows:

class UserController < ApplicationController
def edit_self
@user=User.find(params[:user_id])
#check if you’re editting yourself.
if params[:user_id][email protected]
#edit user
end
end
end

class ModeratorController < UserController
#edit_self is inherited here.
def edit_user
@user=User.find(params[:user_id])
#check if you’re editting a user
if @user.class.name==‘User’
#edit user
end
end
end

class AdminController < ModeratorController
#edit_self and edit_User is inherited here.
def edit_moderator
@user=User.find(params[:user_id])
#check if you’re editting a user
if @user.class.name==‘Moderator’
#edit moderator
end
end
end

Not only am I duplicating the same code as the class before (with an
exception of different validations), but I have to create a separate
view for each method! I just want to wrap up those methods in one
single, inherited method edit_user. Any ideas?

Hi Taro,

Taro wrote:

Sorry, I was in a rush. I’ll try to explain this a little more
thoroughly:

No problem.

Basically, I have user classes set-up as ApplicationController >
UserController > ModeratorController > Admin Controller.

Why the chain? I mean, based on what I see below, Moderator and Admin
could
both inherit from User. Just asking in case there’s there some reason
you
haven’t covered here.

end
end
end

Not only am I duplicating the same code as the class before (with an
exception of different validations),

Different validations may be a good enough reason, in fact a very good
reason, NOT to try to refactor these into a single, parameter driven,
controller method.

I guess the key question I’d have is this. You’ve shown that you have
two
redundant lines of code in each method. The ‘#check if you’re editing a
?’
line is probably just that’; a line. But what’s the level of similarity
between the code blocks behind the ‘#edit something’ comments? It would
be
a pretty straight-forward exercize to put this in application.rb. The
question I’d recommend you focus on is ‘what would that do to the
readability and maintainability of my code’? Refactoring just to reduce
lines of code is not, IMO, a good expenditure of effort. Refactor this
if
you think that you’re going to have to make the same change in 3 places
every time you make any change. OTOH, if you think you may end up
making
changes to one but not the others, then let it be 'til you learn more.

but I have to create a separate view for each method!

No you don’t. As I said earlier, you can pass your instance variables
to
any view you want to use to render them. That attempt will also shed
light
on whether or not your desire to use a single method to process all your
user types is really a viable idea.

HTH,
Bill