Routing Error uninitialized constant - ruby-on-rails

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.

Related

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.

Not hitting controller method using nested resources

I created an Open House for a specific listing. I am now trying to add an RSVP function. I keep getting an error and I can't figure it out. I'm sure it's something stupid, but I'm just not seeing it.
Rake Routes:
rsvp_listing_open_house GET /listings/:listing_id/open_houses/:id/rsvp(.:format) open_houses#rsvp
My Routes:
resources :listings do
member do
get 'like'
get 'unlike'
get 'duplicate'
get 'gallery'
delete 'gallery' => 'listings#clear_gallery'
get 'manage_photos'
get 'craigslist'
get "add_to_collection"
get 'request_photos'
end
resources :open_houses do
member do
get 'rsvp'
end
end
resources :listing_feedbacks do
member do
get 'archive_feedback'
end
end
end
My Controller:
def rsvp
#open_house_rsvp = params[:open_house_rsvp]
agent_id = params[:agent_id]
open_house_id = params[:open_house_id]
OpenHouseRsvp.create(:agent_id => agent_id, :open_house_id => open_house_id )
flash[:notice] = "Your RSVP has been submitted!"
redirect_to listing_open_houses_path
end
View:
<%= link_to "RSVP", rsvp_listing_open_house_path %>
Errors:
ActionController::UrlGenerationError in OpenHouses#index
No route matches {:action=>"rsvp", :controller=>"open_houses", :listing_id=>"5341"} missing required keys: [:id]
According to the error provided, the path helper is already receiving a :listing_id, and is expecting an :id from an open house object, so that it can properly construct the path. Assuming you've got an #open_house object defined in your controller, your path helper should look like this:
<%= link_to "RSVP", rsvp_listing_open_house_path #open_house %>
Hope this helps!
I do not have enough reputation to post comment so just summary the comments from Zoran and Nic above:
rsvp_listing_open_house_path requires 2 params: listing_id, open_house_id, you can use rsvp_listing_open_house_path(#listing, #open_house) or rsvp_listing_open_house_path(#listing.id, #open_house.id)
Make sure you have #listing and #open_house available in your controller action (you may name them differently). Otherwise, you will get the error mentioned in your comment: No route matches {:action=>"rsvp", :controller=>"open_houses", :id=>nil, :listing_id=>nil} missing required keys: [:id, :listing_id]

Rails "No route matches" error

I'm getting the following error in my Rails app:
No route matches {:action=>"edit", :controller=>"customers", :customer_id=>1}
Following is the jobs view line to link to edit customer details (customer has many jobs, but no nested resources):
<%= link_to job.customer_id, edit_customer_path(:customer_id => job.customer_id) %>
Following is edit definition in the controller:
def edit
if params[:customer_id]
#customer = Customer.find(params[:customer_id])
elsif params[:id]
#customer = Customer.find(params[:id])
end
respond_to do |format|
format.html # edit.html.erb
format.json { render json: #customer }
end
end
rake routes gives the following:
edit_customer GET /customers/:id/edit(.:format) customers#edit
NOTE:
If I change the view to:
<%= link_to job.customer_id, edit_customer_path(:id => job.customer_id) %>
then I get the same error but with ":id=nil" (i.e. with no value passed at all):
No route matches {:action=>"edit", :controller=>"customers", :id=>nil}
I am a little new to this, but can someone please explain what is going on?
Thanks!
Update
Try writing your path like this
edit_customer_path(job.customer) if job.customer
In your routes, specify one parameter for customers.
resources :customers, param: :customer_id
so you always know what the id is going to look like. (there is some trickery required to make this work all the way through resources).
Also, another potential issue (which has caught me out a few times) is that I have instantiated on the same page a blank instance of the same class I am trying to route to. eg #customer = Customer.new, which the link to is looking for, but doesn't find an id as the record hasn't been saved.
I find named routes a hassle, and much prefer using polymorphic urls as they degrade gracefully.
In your case it would mean something like this.
link_to 'whev', [:edit, #customer]

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
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.

Rails Routing Incorrectly links to show.html

I'm learning Rails and have encountered some behavior I don't understand. I'm trying to create a simple CRUD app. On the 'new' view after data entry fields and submit button I am trying to add a link that will go to another page (I'll call it 'fnord').
Instead of linking to fnord, it's going to show.html. Given that rails is convention based I wonder if this is a default behavior of some kind, but I haven't been able to figure out what triggers it or the proper way of routing to fnord.
This is Rails 3.2.21, Ruby 1.9.3. I originally generated the model, views and controller using scaffold and then started tweaking things.
Here's my controller (minus unrelated actions - index, destroy, etc):
class EmployeesController < ApplicationController
def show
#employee = Employee.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #employee }
end
end
def new
#employee = Employee.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #employee }
end
end
def fnord
#nothing yet - just trying to get the page to appear right now
end
Here's the relevant code from new.html.erb:
<h2>New Employee</h2>
<%= render 'form' %>
<!-- content, data entry fields, submit button, etc -->
<div>
<%= link_to 'Fnord', employees_fnord_path %>
<div/>
Here's the view, fnord.hmtl.erb:
<h2>Fnord</h2>
<br/>
<p>this is fnord.html</p>
Here's my routes.rb:
MyApp::Application.routes.draw do
resources :employees
get 'employees/fnord'
root :to => 'employees#new'
end
I ran 'rake routes' and get the following output:
employees GET /employees(.:format) employees#index
POST /employees(.:format) employees#create
new_employee GET /employees/new(.:format) employees#new
edit_employee GET /employees/:id/edit(.:format) employees#edit
employee GET /employees/:id(.:format) employees#show
PUT /employees/:id(.:format) employees#update
DELETE /employees/:id(.:format) employees#destroy
employees_fnord GET /employees/fnord(.:format) employees#fnord
root / employees#new
As far as I can see this all looks right, but when I click on the link in new.html it returns show.html, not fnord.html.
The url that shows up in the browser is even locahost:3000/employees/fnord, but the content is from show.html.
I read the routing documentation (http://guides.rubyonrails.org/routing.html) but didn't see any explanations.
I've tried restarting rails (many times) and clearing my browser cache as well and those steps didn't help.
Can anyone enlighten me as to what I'm missing? Thank you very much.
The route for /employees/fnord matches the show route because the show route is looking for URL's in the format: /employees/:id
When you go to /employees/fnord it interprets fnord as the ID of some employee, and it routes it to the show method.
One way to fix it is to declare the /employees/fnord route before the resources routes, so that it matches first:
MyApp::Application.routes.draw do
get 'employees/fnord'
resources :employees
root :to => 'employees#new'
end
Another way is to simply change the name of the URL so that it doesn't match the pattern of /employees/:id:
MyApp::Application.routes.draw do
resources :employees
get 'employees1/fnord', to: 'employees#fnord'
# or whatever
get 'foo', to: 'employees#fnord'
# etc...
get 'employees/foo/fnord', to: 'employees#fnord'
root :to => 'employees#new'
end

Resources