Beginner's routing question: Redirecting to a different controller

73 views
Skip to first unread message

Ronald Fischer

unread,
May 23, 2014, 9:05:36 AM5/23/14
to rubyonra...@googlegroups.com
I have a problem passing control from one controller to the next. Here
are the details:

I have a model 'Dict' with primary key :dictname. I have two
controllers, named 'Login' and 'Dict'. The application starts in
views/login/index.html.erb, where I have - among other stuff - an entry
field for the dictname. When clicking a button, control passes to a
method in login_controller.rb, where various authentification is being
performed.

If all checks pass, control should now be transfered to a page
views/dict/manage.html.erb , and this page should receive the dictname
as a parameter.

Here is what I have tried so far:

In routes.rb I placed an entry

get 'dict/:id/manage', to: 'dict#manage'

In login_controller.rb, I tried to transfer the controll with

redirect_to dict_path(@dict)

However, I get the error message

'undefined method dict_path'

I thought that dict_path should be a helper method, which is generated
out of my routes.rb . Since this method is undefined, I suspect that my
routes.rb is not correct.

Note that I did NOT place a

resources :dicts

into routes.rb, because - for the time being - I don't need yet the full
set of CRUD capabilities on a Dict, so I thought I'll just start with
the minimum needed, and extend over the time as necessary. If you think
that this is an unwise decision, please let me know.

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

Scott Ribe

unread,
May 23, 2014, 9:09:20 AM5/23/14
to rubyonra...@googlegroups.com, Ronald Fischer
On May 23, 2014, at 7:04 AM, Ronald Fischer <li...@ruby-forum.com> wrote:

> into routes.rb, because - for the time being - I don't need yet the full
> set of CRUD capabilities on a Dict, so I thought I'll just start with
> the minimum needed, and extend over the time as necessary. If you think
> that this is an unwise decision, please let me know.

Starting with the minimum you need now and building up is a good idea. BUT you can go ahead and put the resource in the routes if you want. The result of this is that an attempt to access an unimplemented action will simply give you a different error message. (Or you can go ahead and stub in a simple action that just renders a better error.)

--
Scott Ribe
scott...@elevated-dev.com
http://www.elevated-dev.com/
(303) 722-0567 voice




Евгений Шурмин

unread,
May 23, 2014, 9:59:37 AM5/23/14
to rubyonra...@googlegroups.com
get 'dict/:id/manage', to: 'dict#manage' , as: :dict


пятница, 23 мая 2014 г., 17:05:36 UTC+4 пользователь Ruby-Forum.com User написал:

mike2r

unread,
May 23, 2014, 10:03:05 AM5/23/14
to rubyonra...@googlegroups.com, Ronald Fischer
I agree with everything Scott says in his post.  This is a small point, but I don't like having routes defined that aren't really used.  It's a small point, because my solution is also going to lead to a different error, but I prefer to head things off at the source.  I would use resources, as Scott suggests, but limit the actions that you really need such as:

resources :dicts, only: [:show]

resources :dicts, only: [:show, :index]

you get the idea.  you can then relax the restrictions as you build out the functionality.


Scott Ribe

unread,
May 23, 2014, 1:48:03 PM5/23/14
to rubyonra...@googlegroups.com, Ronald Fischer
On May 23, 2014, at 8:03 AM, mike2r <mr...@kalanitech.com> wrote:

> I agree with everything Scott says in his post. This is a small point, but I don't like having routes defined that aren't really used. It's a small point, because my solution is also going to lead to a different error, but I prefer to head things off at the source. I would use resources, as Scott suggests, but limit the actions that you really need such as:

Very good point. My thinking was colored by the fact that I really only do this during development, where I expect to implement the rest of the actions very soon.

Ronald Fischer

unread,
May 25, 2014, 2:20:02 AM5/25/14
to rubyonra...@googlegroups.com
Евгений Шурмин wrote in post #1146886:
> get 'dict/:id/manage', to: 'dict#manage' , as: :dict

Could you please kindly explain, what the effect of the "as: :dict" is
in this case? I understood that I need the "as:" parameter for those
cases where I want to name the route differently, but in this case, it
is always 'dict'.

With other words: What would be the effect if I just leave out "as:
:dict"?

Ronald Fischer

unread,
May 25, 2014, 2:31:33 AM5/25/14
to rubyonra...@googlegroups.com
mike2r wrote in post #1146887:
> I would use resources, as
> Scott
> suggests, but limit the actions that you really need such as:
>
> resources :dicts, only: [:show]

Now in my case, the action has a "non-standard" name, i.e. ":manage".

Can I use this too in the "only:" array, or should I instead use a
standard action (in this case probably "edit"), which then, inside my
controller, invokes the "manage" method?

From my understanding of the "Rails Routing From The Outside" guide,
routes.rb defines which controller methods are invoked, when a certain
request arrives, and the "resources" definition just creates standard
routes with standard action names for the "common case"
(show/index/edit/....). Did I grasp this correctly?

If I understood this right, I would have two possibilities: Use ab
action name which reflects the purpose of the action (here: 'manage')
and write a special route definition, as Евгений Шурмин suggested above,
or use the standard action names, and use a 'resources' definition. From
a viewpoint of maintainability, what would you consider the better
solution?

mike2r

unread,
May 25, 2014, 12:58:01 PM5/25/14
to rubyonra...@googlegroups.com
To answer your first question, when a segment key is part of your route (:id) you need to tell rails what you want the named route to look like or it won't generate one.  Even if you didn't have the segment key, for example:

get 'dict/manage' => 'dict#manage'

it would generate the named routes dict_manage_path and dict_manage_url which isn't what you want.  Therefore, you need the as: :dict to generate the named route you are after.  

In answer to your second question, yes, you have grasped the basics correctly and yes.  The resources statement creates the standard routes as well as the named routes to go with them.  However, it's part of a larger architecture of handling REST transactions.  When you use the following:

rails generate scaffold dict

it will generate not only the routes statement, but the standard actions and views to go with it.  If you stick to the rails convention, it will save you a lot of time and work, and I advise that you do so unless there is functionality that just won't work with that structure.

I would argue that from your description (i'm at a little bit of a loss since I haven't actually seen your controller code), dict is a resource, even if you don't intend to initially offer users full CRUD options on the resource.  Therefore, I prefer setting this up in the routes (and elsewhere) as a resource and using standard Rails action names.  The word "manage" to me could be adding a new entry to dict, modifying an existing entry, etc.  This actually involves a number of actions and it would be better to more specific about the purpose of each action.  By the way, edit actually involves two actions.  The first is to provide the user with a form populated with the values of the existing entry to be edited.  The second happens when the user makes changes and submits the form, and the resource is updated.  In the Rails architecture, these are the edit and update actions respectively and you would need to allow both in your resources statement.

If you don't like the Rails standard names for your routes, you can change them, although I still maintain it's better to learn the Rails way of doing things and stick to it when possible.  This makes maintenance and integration with other parts of your application much easier.  However, in this case, let's assume we want to say manage instead of edit.  You would route as follows:

resources: :dicts, path_names: { edit: 'manage' }

Note:  this changes the path name, so you will have /dicts/:id/manage, but it doesn't change the controller actions, it will still map to the action edit in the controller.  Usually this is only done when there are specific reasons to do so, such as creating a site in a different language where you want the URL's to reflect a language other than English.  



Ronald Fischer

unread,
May 25, 2014, 1:40:40 PM5/25/14
to rubyonra...@googlegroups.com
Thanks a lot for the detailed explanations. Two remarks for this:

As for the naming, my application evolves a dictionary of foreign
language idioms, and the main purpose it to train the user in the usage
of these idioms. From the perspective of the user, there are 3 types of
"screens" (HTML pages):

- The login page (where he identifies himself, chooses (or create) a
dictionary)

- The Management page (where he can import/export dictionaries to/from
database, merge other dictionaries into the existing ones, add new
idioms (this is really an "edit" action) and, most important of all,
select one of several training plans and start trainig).

- The Training page, where an idiom training is performed on the fly.
This page also allows, for convenience, editing vocabulary on the fly
(but only the one which is presented right now).

From this setup, I found that the usual CRUD actions don't go that well
with the application, and that's why I invented the action "manage" in
dict, and in the meanwhile the action "start" in the (new)
training_controller. However I am flexible with names, and if an
experienced Rails developer strongly suggests going with standard action
names, I certainly don't object. After all, I can still keep the "meat"
of my code in my "manage" routine, and just have the "edit" method call
"manage()".

As for "generate scaffold", I have used this when doing exercises back
with good old Rails 1, but now with Rails 4, the tutorial doesn't use
"generate scaffold" anymore, but always "generate model" and "generate
controller". Do you recommend me to investigate into "generate scaffold"
too?

Thanks a lot for your detailed comment. It really helps a lot!

One final question: I have read various tutorials, but when it comes to
look up the API, I found the documentation a bit confusing, and
difficult to find what I am looking for. You gave for example a
suggestion to use the "resources" method with the path_names: parameter.
Though I have stumbled several times over the usage of 'resources', I
haven't found a single place, which would explain the usage of all
parameters (such as path_names:) and examples of usage. Right now, when
I really want to know how something is done in Rails, I google for it,
hoping that someone else had the same problem. This often works out, but
I would be more happy if I had a documentation of the Rails classes and
methods, in a similar way as it is for Ruby and the standard functions
and -classes. Is this available, or is Rails in the flux so much that we
can't expect this yet?

mike2r

unread,
May 26, 2014, 10:53:55 AM5/26/14
to rubyonra...@googlegroups.com
OK, this gives me some more information, but I'm still not completely sure I understand the application.  It sounds like a given user can have one (or more?) dictionaries associated with the user and that each dictionary has one or (probably) many idioms associated with it.  In this case, dict is a resource.  If I read this right, in your initial application a user could create a dictionary.  I'm assuming that you may, in later development, have the option to edit a dictionary (which is different from editing an idiom), or delete a dictionary.  However, you also have elements such as import and export that are not standard CRUD actions.  You've included them in an action manage, but I have a feeling that import and export may be also be separate actions.  I'm making some assumptions here which I frequently have to do when answering posts on this list, and if I've assumed incorrectly, that will affect my answer.

In that case, you would need to extend the resource to include actions in addition to the standard new, create, edit, update, show, index, and destroy actions.  In this case, let's assume we want to add the action manage.  You would do that as follows:

resources :dicts do
   member do
      get :manage
   end
end

This differs from path_names.  path_names changes the name of the path but does not otherwise affect the routing or actions associated with the resource.  The above code adds manage as a separate action, and creates the appropriate routing and named paths to go with it.

With respect to the scaffold generator, yes, I believe it is worth using, but there are developers that would disagree and don't use it.  Some of the tutorials, such as the railstutorial.org tutorial that is commonly referenced on this list, have you use the controller generator and model generator so that you learn the concepts involved by being forced to manually create a lot of the elements.  I believe this is appropriate and a good approach for a tutorial.  Likewise, the same tutorial takes you through the steps of manually creating a user resource and authentication.  Again, you should, IMO, understand these concepts.  However, there are are some ways to make your development more efficient once you have mastered these concepts.  The scaffold is one of them. Typically, I start with a scaffold and generally modify it to fit the particular needs of that resource.  Likewise, I don't usually (never) roll my own authentication, I use the Devise gem.  

With respect to documentation, it is true, Rails changes quickly (IMO, mostly for the better) and sometimes the documentation will lag a bit.  I believe, in general, the Edge Guides are well done and would recommend them.  There are a few cases where they may not be as comprehensive as you might need.  There is one other resource I would recommend.  The Rails 4 Way is a book you can buy from leanpub.com.  I don't have any connection to the book or that site, but if you buy it from them, you automatically get any updates to the book and they update fairly regularly.  This is, IMO, an excellent reference.  I would not use it to learn Rails basics.  It's fairly advanced and would not be appropriate until you have mastered the basics through a tutorial, but it covers the topics you asked about better than any other resource I know of.  Hopefully, others have some input here as I'm sure there are resources I'm not aware of.  The Railscasts are also good, but I'm not sure if they're being maintained and updated at the moment.

The classes and methods themselves are documented in the Rails API (api.rubyonrails.org).  For example, at api.rubyonrails.org/classes/ActionView/Helpers/Urlhelper.html you will see all the methods and options for button_to, link_to, mail_to, etc. that you use in view rendering.

Ronald Fischer

unread,
May 27, 2014, 2:36:53 AM5/27/14
to rubyonra...@googlegroups.com
You did grasp the concept of my application amazingly well, only that
the only possible ways to "edit" a dict is to add and remove idioms
(would you see this as editing the dictionary, or as manipulating the
Idiom class?).

The reason why I did not follow the CRUD way - and maybe this I was
mislead here - was the following:

When starting the design, I started with a concept of the screens the
user is going to see. The initial screen will present an entry form for
the name of the dictionary, the user name, buttons for creating and
opening a dictionary, and - for the creation case - an entry field
denoting a dictionary type (think about it as the "language" for the
dictionary, but the concept is more general).

After clicking one of the buttons, a new screen appears from where the
user can click various buttons - exporting the dictionary, start one of
three predefined training types, manually adding idioms to the
dictionary (but on this screen no possibility of deleting or editing
idioms, nor for the deletion of the dictionary).

My idea was that the logic for each web page should correspond to one
controller method. In this case, I have used two different controllers:
For the entry page I have a login_controller (because I would like to
add password authentification later on), and for the second form I have
a dict_controller.

Similarily, I am planning a training_controller for doing the idiom
training, and another controller (maybe idiom_controller) for adding,
deleting and editing individual idioms.

Maybe this mapping "web page" to "controller" is, from the onset, bad
design?

mike2r

unread,
May 27, 2014, 7:41:05 PM5/27/14
to rubyonra...@googlegroups.com
Web pages would be more likely to map to a controller action, not to a controller.  It's common to start by laying out your web pages and then working back from there.  However, I'll warn you it's usually a back and forth process.  Once you have the web pages laid out, you need to establish a structure that usually involves grouping pages to controllers that follow Rails conventions.

In this case, you have at least three resources:  user, dict, and idiom.  You ultimately will most likely have more.  I would recommend you go through the tutorial at railstutorial.org because it does a very good job of introducing these concepts and you will really need to understand this when you introduce password authentication.  

Editing a dict resource would not be adding and removing idioms, that would be the create and destroy actions of the idiom resource.  Editing a dict resource would involve renaming the dictionary or changing the dictionary type.  

Rails comes with a default set of actions related to a resource but you don't have to use all of them.  It's also not a perfect science.  A good example is your training screens.  That might be its own resource, it might just be an extension of the idiom resource, or it could be its own controller but not correspond to a resource.  It depends on how much functionality there is.  Not everything will fit into a resource.  For example, many applications have static pages such as a home page, an "about us" page, etc.  I usually group those into a pages controller which stands on its own, it has no resource or model behind it.  Again, the tutorial will do a much better job of explaining this.

Ronald Fischer

unread,
May 28, 2014, 2:55:59 AM5/28/14
to rubyonra...@googlegroups.com
Thank you for the suggestions. I went through the tutorial found on the
web (which was explaining the concepts using the example of making a
blog site), but could relate what I have learned, only to the concept of
the idioms in my project, but not to the rest of my application.

I now see that is a good idea to treat the user as its own resource,
because sooner or later I will need this anyway, and I will try to
redesign my application.

mike2r

unread,
May 28, 2014, 10:41:44 AM5/28/14
to rubyonra...@googlegroups.com
When you get to the point where you are going to use password authentication, re-read the user authentication part of the tutorial.  Right now, you have login mapped to an index action.  Actually, login uses the concept of a session resource and you create a session when you log in.  You will want to understand that concept and how a session store is used to maintain security.

Good Luck. 

Ronald Fischer

unread,
May 28, 2014, 12:37:36 PM5/28/14
to rubyonra...@googlegroups.com
mike2r wrote in post #1147433:
> On Wednesday, May 28, 2014 2:55:59 AM UTC-4, Ruby-Forum.com User wrote:
>> --
>> Posted via http://www.ruby-forum.com/.
>>
>
> When you get to the point where you are going to use password
> authentication, re-read the user authentication part of the tutorial.

Thanks, I will do so. I already started to read the tutorial you
recommended, and I must say it's really well written!

Ronald
Reply all
Reply to author
Forward
0 new messages