Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add routes for a new template?

I am new in Ruby and Rails and little bit confused about rendering and adding routes for a new template.

I have following link_to tag

<td colspan="3">
 <%= link_to 'Show Current State', simulation, :action => :current_state, :class => 'btn btn-primary'%>
</td>

Where simulation is the name of controller and action is name of the method in SimulationController.

I added this in my routes.rb

  resources :simulations, except: [:edit]

  resources :simulations do
    collection do
     get 'current_state'
     post 'current_state'
   end
 end

In my SimulationController class I added a new method i.e.

  def current_state
   byebug
  end

My problem? routes is not re-directing to current_state method. Instead, it is redirecting to http://localhost:3000/simulations/{someID}

This redirection is calling show action.

def show
 ...
end

How can I make this work out and make <%= @simulation.dat %> line accessible in new.html.erb. Location of new.html.erb is in following path

views/simulations/index.html.js
views/similations/show.html.js
views/simulations/new.html.erb

This could be a basic question but I am new to rails 4. Thanks in advance.

Edit-1

Def of get_state method in controller

 def get_state
  @simulation = current_user.simulations.find(params[:id])
  return not_found if @simulation.nil?  
  .....
  /// How to send `@simulation` into `state.html.erb` formally as `new.html.erb`
end
like image 411
Mike phawn Avatar asked Jul 04 '15 22:07

Mike phawn


People also ask

What is a route template?

A Route template is as its name implies a template for a route, which is used to create routes from a set of input parameters. In other words, route templates are parameterized routes. Route template + input parameters ⇒ route. From a route template you can create one or more routes.

What is routing in C#?

Routing is used to map requests to route handlers. Routes are configured when the application starts up, and can extract values from the URL that will be used for request processing.


1 Answers

You have too many misses in your code.

First, You don't need 2 resources :simulations, just merge them into one:

resources :simulations, except: :edit do
  member do
    get 'current_state', action: 'get_state'
    post 'current_state', action: 'change_state'
  end
end

Note that the original collection block is changed to a member block.
The difference between a collection block and a member block is that you need to provide an resource id for each routes in the member block, while no resource id is required for those in the collection block.

Also note that I added action: 'xxx' in each route, so you have to add these 2 actions in your SimulationsController, one for GET requests, and the other for POST requests.

UPDATE

In both of these actions, add render 'new' at the end.

END OF UPDATE

Run rake routes in your console (or bundle exec rake routes if you have multiple versions of rails installed), and you will see all the routes along with there url helper methods listed, like this:

                   Prefix Verb URI Pattern                    Controller#Action
current_state_simulations GET  /simulations/:id/current_state simulations#get_state
current_state_simulations POST /simulations/:id/current_state simulations#change_state
...

According to the Prefix column, the link in the view should be

<%= link_to 'Show Current State', current_state_simulations_path(simulation), :class => 'btn btn-primary'%>

Or in short

<%= link_to 'Show Current State', [:current_state, simulation], :class => 'btn btn-primary'%>

UPDATE FOR Edit-1

Don't return in actions, because return doesn't stop rendering.
Instead, use raise ActionController::RoutingError.new('Not Found') to redirect users to the 404 page.

You can define an instance method in ApplicationController:

class ApplicationController < ActionController::Base
  private
  def not_found!
    raise ActionController::RoutingError.new('Not Found')
  end
end

And modify your SimulationsController:

def get_state
  @simulation = current_user.simulations.find(params[:id])
  not_found! unless @simulation
  # ...
  render 'new'
end

Best Practice
For dynamic page web applications, don't render views for non-GET requests!

Why? Because if a user POSTs some data to your web app, and then refreshes his/her browser, that request gets POSTed again, and your database got tainted. Same for PATCH, PUT and DELETE requests.

You can redirect the user to a GET path if the non-GET request succeeds, or to a 400 page if the non-GET request fails.

like image 108
Aetherus Avatar answered Nov 25 '22 06:11

Aetherus