Nynevi
Nynevi

Reputation: 1

Routing in Rails has problems with Controller/action/id route

In my Rails 4 application I create pages through a PagesController to form a menu. The menu has links to redirect_to index action of the appropriate controller. Columns for that Page model are :id, :title, :access_level, :html (actually refers to the controller), :icon

Example data is: 5, Employees, 3, employees, users

NOTE: Irrelevant parts of code such as "resources :employees" are not visible!

Routes file:

resources :pages
resources :access

PagesController:

def show
  @pages = Page.find(params[:id])
  redirect_to controller: "#{@page.html}", action: "index"
end

Block to generate links

<% @pages = Page.all %>
<% @pages.each do |page| %>
<li>
    <%= link_to({ controller: "pages", action: "show", id: "#{page.id}" }) do %><i class="fa fa-<%= page.icon %> fa-fw"></i> <%= page.title %>
    <% end %>
</li>
<% end %>

HTML Generated link_to based on the example:

<a href="/pages/5"><i class="fa fa-users fa-fw"></i> Employees</a>

Everything works fine except when I try to implement a basic login system but get the following error:

ActionController::UrlGenerationError in Access#index
Showing C:/Users/Samsung/Documents/rails/AjansTakip/app/views/access/index.html.erb where line #9 raised:

No route matches {:action=>"attempt_login", :controller=>"access"}

Index.html.erb Line 9 of Access View

<%= form_for :access, url: {action: "attempt_login"} do |f| %>

AccessController (:id_number is short for identification_number and has no relation to :id)

def attempt_login
    if params[:id_number].present? && params[:password].present?
        found_user = Employee.where(id_number: params[:id_number]).first
        if found_user
            authorized_user = found_user.authenticate(params[:password])
        end
    end
    if authorized_user
        redirect_to controller: 'pages', action: 'index'
    else
        redirect_to action: 'login'
    end
  end

I am following Lynda Rails 4 Essential Training and I am unable to pass the first part of the implementation of the basic login system therefore please do not comment on any part of coding other than routing since I am trying to learn it on my own.

As far as solutions I tried this one which works to pass the error to bump into another one

get 'access/attempt_login', to: 'access#attempt_login'

but I am pretty sure there is a better way of handling these kind of situations. I get another error when I submit the form via post on index.html.erb:

No route matches [POST] "/access/attempt_login"

I think the problem arises because of the default routing which is :controller(/:id(/:action)) and that the controller expects an :id before the :action. I see no point in routing "get" for all kind of actions that do not require an :id.

Another solution that I used was to change the default routing to ":controller(/:action(/:id))" but this causes even more problems than it solves (we might even say it does not solve anything at all). Even the links in the menu break because link_to :action "show" does not get parsed as href="pages/show/5". I also tried generating links as link_to({ controller: "pages", action: "show", id: "show/#{page.id}" }) but this is nowhere as practical and dynamic as I would want to be.

Please point me in the right direction. I am also willing to change how Paging works with the PagesController, I could not think of a better way of storing pages in a database and redirecting them all in one place.

Thanks

Upvotes: 0

Views: 728

Answers (1)

agmcleod
agmcleod

Reputation: 13621

Yeah don't use the default controller stuff, that's old school. Instead, give this a try:

Delete the get line:

get 'access#attempt_login', to: 'access#attempt_login'

Now, since you want it on a collection of the resource, try this:

resources :access do
  collection do
    get :attempt_login
  end
end

Then in your form:

 <%= form_tag attempt_login_access_path, method: :get do |f| %>

I use form_tag when it comes to urls that aren't for create or update actions. Form_for is good when you have a model present. The method get is also important, as forms default to post. You may need to double check that route path:

bundle exec rake routes | grep attempt

And ensure the method is right.

Upvotes: 3

Related Questions