How to add routes for a new template? - ruby-on-rails

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

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.

Related

Rails button call controller method and don't redirect

I am trying to call a method in a controller from a button in a Rails view. I followed some other questions on here and got to this point.
routes.rb:
namespace :processing do
resources :applications do
stuff
post :test, :to => 'applications#test', :on => :member
end
end
the controller method is simply called test. Here is the relevant part of the controller:
def test
#application = Application.find_by(record_id: params[:id])
puts 'THIS IS A TEST'
end
Finally, I am calling the route with this code in an .erb file:
<%= button_to 'Send to Processing',
test_processing_application_path(record_id),
method: :post, form_class: 'btn btn-danger' %>
The button renders properly and seems to follow the right route. However, my problem is that the button attempts to redirect and render the route
/processing/applications/715707082/test which doesn't exist and causes a problem.
How do I just make this button not redirect/render something and instead simply call the method from the page it is currently on? Please feel free to link me relevant posts or close this if it duplicates an existing question.
The route in your routes.rb file does define the
test_processing_application_path as a POST to the path
/processing/applications/:id/test(.:format)
expecting to be implemented in the controller
processing/applications#test --
that is a file in app/controllers/processing/applications_controller.rb that defines a controller like:
module Processing
class Applications < ApplicationController
def test
# your code here
end
end
end
Instead of using a method you should use action and remote true will trigger an ajax request and prevent you from redirection. Then create a test.js.erb file for handling ajax request to update your DOM that will be executed after your action call.
<%= button_to 'Send to Processing',test_processing_application_path(record_id),
action: :test, form_class: 'btn btn-danger', :remote=>true %>
Hope this will help.
Cheers.

Link to another view using ruby in windows

I am doing a simple CR and trying to put some link/button(add,edit etc), when the user will click the add it will direct to that view..
Question: How should I indicate which view will be load when I click the specific link/button?
Index.html.erb
<h1>My First CRUD!</h1>
<%= link_to "Add Page", posts_path %>
<%= link_to "Edit Page", posts_path %>
<%= link_to "Showx Page", posts_path %>
Posts Controller
class PostsController < ApplicationController
def index
end
def addItem
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:item, :description)
end
end
Routes
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
resources :posts
root "posts#index"
resources :posts
root "posts#addItem"
You can declare all the root routes that you want in your routes.rb, but it'll take just the one that was declared first, it doesn't matter if the definition has some mistake, it won't tell you.
And the route where the link_to will redirect is what you declare as second argument (in this case).
In your example you have three link_totags, which are pointing to the same path. If you'd like to make the "Edit" link_toredirect to the posts#edit method you firstly must create the edit method in your posts_controller and then add it to your route as:
get '/posts/edit/:id', to: 'posts#edit'
But in your case as you have resources :posts it makes the whole work for you and creates all the routes defined in the posts#controller, what resources do is to map a number of related requests to actions in a single controller, that's to say;
When Rails application receives a request for:
GET /posts/edit/1
That's what happen when you go to edit the a certain post by passing the id of 1, then it asks the router to map it to a controller action. If the first matching route is:
resources :posts
Then Rails dispatchs that request to the edit action on the posts controller with { id: '1' } in params.
Short answer, to create a common <a> tag create a link_to, add a text to specify to where will this redirect, then the route that you've defined, you can check them by running rails routes if you're using Rails 5 or bin/rake routes if you're with Rails < 5.

Routing Error uninitialized constant

I am trying to learn RoR.
MY controller is
class SectionController < ApplicationController
def new
if request.post?
u=SectionMst.new( :section_name => params[:section_name])
u.save
redirect_to("/section")
else
render
end
end
def index
#sections = SectionMst.all
end
def destroy
u=SectionMst.destroy(params[:id])
u.save
redirect_to("/section")
end
def edit
#user = SectionMst.find(params[:id])
end
end
and index.html.erb is
<%= link_to "Edit", edit_section_path(section.id), method: :edit %>
rake routes is
section_new POST /section/new(.:format) section#new
POST /section/:id/edit(.:format) section/:id#edit
section_index GET /section(.:format) section#index
POST /section(.:format) section#create
new_section GET /section/new(.:format) section#new
edit_section GET /section/:id/edit(.:format) section#edit
section GET /section/:id(.:format) section#show
PUT /section/:id(.:format) section#update
DELETE /section/:id(.:format) section#destroy
routes.rb is
post "section/new"
post "section/:id/edit"
resources :section
i am getting the
Routing Error
uninitialized constant Section
if i delete the second line of routes.rb
then i get
Routing Error
No route matches [POST] "/section/3/edit"
not able to get why???
Get rid of the first and second lines in your routes.rb. They're redundant. The resources will create these lines automatically.
The resources :section should be written as resources :sections. Notice that it's plural.
In your index.html.erb, you shouldn't mention method: at all. It's automatically set, and :edit as method doesn't exist. Method refers to put or get or delete, but you normally don't have to mention it.
You do not need this lines in your routes.rb
post "section/new"
post "section/:id/edit"
Change the third line to:
resources :sections #plural
If you delete them, you can hit the edit view using
<%= link_to "Edit", edit_section_path(section.id), method: :edit %>
which will hit your app at section/3/edit with a GET request.
In your edit.html.erb, you can then have fields to capture edits and do a PUT to /section/3.
Note that RAILS uses HTTP verbs to define the CRUD operations. Ref here.
Check your controller's file name because it should be plural. It is supposed to match the class name. So, you should rename app/controllers/section_controller.rb to app/controllers/sections_controller.rb.

Rails - Add action to controller created by scaffold

I'm trying to add an action called rollback to controller.
As I've seen, the only things I should do is writting the new action:
def rollback
puts "ROLLBACK!"
respond_to do |format|
format.html # index.html.erb
format.json { render json: #components }
end
Modify the routes.rb file:
resources :components do
collection do
post :rollback, :as => 'rollback'
end
end
And calling the action from some view:
<%= link_to 'Rollback', rollback_components_path %>
But I get the following error:
Couldn't find Component with id=rollback
app/controllers/components_controller.rb:18:in `show'
That's because instead of going to rollback action, the controller thinks that we are trying to 'show' to component with id 'rollback'.
Something that it seems weird for me is that calling 'new' action rails uses new_component_path (without s, in singular), but if I write rollback_component_path it throws me an error and I cant see the view.
In your routes you require a POST, just clicking a link is by default a GET, so either write
resources :components do
collection do
get :rollback
end
end
and then the link_to will work as expected.
I am assuming the rollback operation is not idempotent, so a POST is semantically better in that case.
If you write your link as follows, then rails will create an inline form for you:
link_to 'Rollback', rollback_components_path, :method => 'post'
Hope this helps.
This will work
routes.rb
resources :components
match "components/rollback" => "components#rollback", :as => :rollback
In views
<%=link_to 'Rollback', rollback_path%>

Button to Execute Ruby Without Javascript

Route
resources :cars do
collection do
get :f01a
end
end
Controller
class CarsController < ApplicationController
def f01a
#user = User.find(params[:id])
#count = Count.find_by_user_id(#user)
#count.increment!(:f02)
redirect_to #user
end
end
View
<%= button_to "add f01", f01a_cars_path %>
I can't get this to work. I need to execute this code from a button.
button_to sends a POST request, but your routing is setup to only accept GET requests. You should change it to:
resources :cars do
collection do
post :f01a
end
end
Since you're using params[:id] in your action, but not sending it in at all, you'll need to pass it in your button_to:
<%= button_to "add f01", f01a_cars_path(:id => something)
(Replace something with whatever ID you want to pass.)

Resources