undefined method `_path' in form, with routes defined at :resources - ruby-on-rails

I've been stuck on this for a bit and can't figure out the exact reason why I'm getting the following error:
undefined method `entries_path' for <%= form_for(#entry) do |f| %>
entry_controller:
class EntryController < ApplicationController
def index
end
def new
#entry = Entry.new
end
def create
#entry = Entry.new(user_params)
if #entry.save
redirect_to #entry
else
render 'new'
end
end
private
def user_params
params.require(:entry).permit(:comment, :flag)
end
end
routes has:
resources :entry
and the new page where the error occurs:
<%= form_for(#entry) do |f| %>
<%= f.label :comment %>
<%= f.text_field :comment %>
<%= f.label :flag %>
<%= f.text_field :flag %>
<% end %>
I can't figure out why I'm getting this error.

form_for needs to reference the path associated with #entry (i.e. entries_path), but your routes.rb file uses the singular form of the resource (:entry) rather than the required plural form (:entries), so the proper path names don't exist.
Rails models use the singular form, but the Rails database, controllers, views use the plural form and this is reflected in the routes file. One way to remember this is that a model is describing a single class that each object belongs to. Everything else, pretty much, is responsible for managing multiple instances, so while they themselves are singular (e.g. Controller), they refer to the objects they manage in the plural form (e.g. EntriesController, controller/entries directory).
See Ruby on Rails plural (controller) and singular (model) convention - explanation for more discussion of this.

Controller and views should always be treated in plural form. For example, if you have an object Book, then the controller declaration should be
class BooksController < ApplicationController
and the views( new, edit, show, index ) should be inside a folder named
/books
Also, the declaration of routes should be in plural form. In this case, the routes should be declared as
resources :books
You could try to generate the controller and view folder by running in your terminal:
rails generate controller name_of_object_in_plural_form( for sample, books)
The script will generate a controller named books_controller.rb and /books folder under /views

Related

Routing Error: No route matches [POST] "/flex_quiz/new"

In my rails app I'm trying to use a form partial to display the same quiz on the new and edit views. I can see the new view page, but when I hit <%= f.submit "Submit Answers" %> I get an error saying No route matches [POST] "/flex_quiz/new".
Here is the form for line in my partial:
<%= form_for #flex_quiz, url: url do |f| %>
And here's how the locals stand in my new view:
<%= render partial: "quiz", locals: { url: new_flex_quiz_path, method: :post } %>
And my edit view:
<%= render "quiz", url: edit_flex_quiz_path(#flex_quiz), method: :put %>
Here are the route paths:
Prefix Verb URI Pattern Controller#Action
...
flex_quiz_index GET /flex_quiz(.:format) flex_quiz#index
POST /flex_quiz(.:format) flex_quiz#create
new_flex_quiz GET /flex_quiz/new(.:format) flex_quiz#new
edit_flex_quiz GET /flex_quiz/:id/edit(.:format) flex_quiz#edit
flex_quiz GET /flex_quiz/:id(.:format) flex_quiz#show
PATCH /flex_quiz/:id(.:format) flex_quiz#update
PUT /flex_quiz/:id(.:format) flex_quiz#update
DELETE /flex_quiz/:id(.:format) flex_quiz#destroy
Can anyone suggest how to fix this? I have looked at several similar posts (like this and this) but since I'm using partials the solution here is going to have to be a bit different.
EDIT
Here are my definitions in my flex_quiz_controller:
class FlexQuizController < ApplicationController
before_action :require_sign_in
def show
#flex_quiz = FlexQuiz.find(params[:id])
end
def new
#flex_quiz = current_user.build_flex_quiz
end
def create
#flex_quiz = FlexQuiz.new
#flex_quiz.flex01 = params[:flex_quiz][:flex01]
#flex_quiz.flex02 = params[:flex_quiz][:flex02]
#flex_quiz.flex03 = params[:flex_quiz][:flex03]
#flex_quiz.flex04 = params[:flex_quiz][:flex04]
#flex_quiz.flex05 = params[:flex_quiz][:flex05]
#flex_quiz.flex06 = params[:flex_quiz][:flex06]
#flex_quiz.flex07 = params[:flex_quiz][:flex07]
#flex_quiz.flex08 = params[:flex_quiz][:flex08]
#flex_quiz.flex09 = params[:flex_quiz][:flex09]
#flex_quiz.flex10 = params[:flex_quiz][:flex10]
#flex_quiz.user = current_user
if #flex_quiz.save
flash[:notice] = "Quiz results saved successfully."
redirect_to user_path(current_user)
else
flash[:alert] = "Sorry, your quiz results failed to save."
redirect_to welcome_index_path
end
end
def edit
#flex_quiz = FlexQuiz.find(params[:id])
end
def update
#flex_quiz = FlexQuiz.find(params[:id])
#flex_quiz.assign_attributes(flex_quiz_params)
if #flex_quiz.save
flash[:notice] = "Post was updated successfully."
redirect_to user_path(current_user)
else
flash.now[:alert] = "There was an error saving the post. Please try again."
redirect_to welcome_index_path
end
end
private
def flex_quiz_params
params.require(:flex_quiz).permit(:flex01, :flex02, :flex03, :flex04, :flex05, :flex06, :flex07, :flex08, :flex09, :flex10)
end
end
If you want to create new flex_quiz objects, then you're going to want to POST to flex_quiz_index_path.
Notice in your route paths, if you look at new_flex_quiz, the HTTP verb is a GET.
It may be slightly unintuitive, but the new action is actually a GET request.
The action in which the object is supposed to be created in is the create action.
So to solve your problem this should do the trick:
<%= render partial: "quiz", locals: { url: flex_quiz_index_path, method: :post } %>
EDIT:
Instead of defining locals, you can simply define your forms in form_for as such:
You will also have to define #flex_quiz in your controller actions as well (in your case new and edit) form_for will automatically infer the appropriate URL.
From documentation:
However, further simplification is possible if the record passed to
form_for is a resource, i.e. it corresponds to a set of RESTful
routes, e.g. defined using the resources method in config/routes.rb.
In this case Rails will simply infer the appropriate URL from the
record itself.
You'll also need to change the naming from singular form to plural.
The rails to do resuable forms is:
app/views/flex_quiz/_form.html.erb:
<%= form_for(#flex_quiz) do |f| %>
# ...
<% end %>
app/views/flex_quiz/new.erb:
<h1>Create a new quiz</h1>
<%= render 'form' %>
app/views/flex_quiz/edit.erb:
<h1>Edit a quiz</h1>
<%= render 'form' %>
While using locals can often be a good idea its not needed here. Note we just pass the resource and not a URL to form_for - that is convention over configuration in action and is what makes Rails awesome.
Rails figures out all by itself what URL to use for the action attribute and what method to use based on if the resource has been saved.
However for this to work you to actually follow the conventions. Make sure you are using the proper plural forms (the plural of quiz is quizzes):
resources :flex_quizzes
class FlexQuizzesController < ApplicationController
end
Unfortunately when it comes to rest of your setup you need to revisit the drawing board. Its not very realistic to think that you can do this with a single model. You would usually have several models with relations:
class Quiz
has_many :questions
end
class Question
belongs_to :quiz
has_many :answers
end
class Answer
belongs_to :question
end
class UserQuiz
belongs_to :user
belongs_to :quiz
end
class UserAnswer
belongs_to :question
belongs_to :answer
end
You would use one or several controllers to let admins create the quizes and a separate controller to let users answer the quiz. Its a quite common domain so you should be able to find plenty of examples.

name error uninitialized constant path in rails

I'm trying to make a form that will post to a database, I'm really struggling at the moment and i'm getting this error.
NameError in AddController#index
uninitialized constant AddController::Newevents
Could you advise what i would need to do?
Heres all the code i have
Form
<%= simple_form_for(#newevent) do |f| %>
<%= f.input :eventname, required: true %>
<%= f.input :eventdate %>
<%= f.input :eventimage %>
<%= f.button :submit %>
<% end %>
controller
class AddController < ApplicationController
def index
#newevent = Newevent.new
end
end
Model
class Newevent < ActiveRecord::Base
def event_params
params.require(:Newevent).permit(:eventname, :eventdate, :eventimage)
end
end
Routes
resources :add
Edit
i now have this error undefined methodnewevents_path'` after changing this
#newevents = Newevent.new
It seems that you miscopied your code here. The error message indicates that your index method actually looks like this
def index
#newevent = Newevents.new
end
Remove the s from the end of Newevent and it should work.
RE: your edit
Your routes declare that you have a resource named add, if you want to show and create your Newevent objects, then you should create a controller for that. Declare resources :newevents in your routes and create a controller to handle it.
You should research RESTful routes, because that's what Rails's resource routing works best with. The form to create a new object should be displayed by the new action and not index.
You should be using create method instead of index if you are using POST http method. index will be called if you are using GET method and it shouldn't be used to post the form data. Refer this link for more information on rails routing.
class AddController < ApplicationController
def create
#newevent = Newevent.new
end
end

How to pass params to new view in Ruby on Rails app?

I'm trying to make simple app. I input my first name and last name to simple <%= form_for #data do |f| %> rails form and after submitting it, app should render simple text like this. My first name is <%= data.first_name %> and my last name is <%= data.last_name %>. I don't know why but my app is saying this error:
undefined local variable or method `data' for
It's probably saying it because no params are passed to view.
Here is my code.
routes.rb
resources :data, only: [:new, :create, :index]
data_controller.rb
class DataController < ApplicationController
def new
#data = Data.new
end
def index
end
def create
#data = Data.new(data_params)
if #data.valid?
redirect_to #data
else
render :new
end
end
private
def data_params
params.require(:data).permit(:first_name, :second_name)
end
end
/views/data/new.html.erb
<%= form_for #data do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :second_name %>
<%= f.text_field :second_name %>
<%= f.submit 'Continue', class: 'button' %>
<% end %>
/views/data/index.html.erb
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= data.first_name %>.</p>
<p>And my second name is: <%= data.second_name %>.</p>
/models/data.rb
class Data
include ActiveModel::Model
attr_accessor :first_name, :second_name
validates :first_name, :second_name, presence: true
end
Please help to find out why params are not passing to next page. Thanks anyways :D
Your view should look like this:
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= #data.first_name %>.</p>
<p>And my second name is: <%= #data.second_name %>.</p>
Also, I would suggest that calling a model something generic like Data is not a very Rails-y approach. Generally, domain models correspond to real-world things like User and Article, which are easy to understand and relate to. It'll get confusing quite fast if you use need to make another model and want to call it Data2 or something :)
Edit:
Since you specified that you do not wish to use the database, I would recommend passing in the object params through the redirect:
redirect_to(data_path(data: #data))
and in your controller's index method:
def index
#data = Data.new(params[:data])
end
Now your view should render properly, since you're passing the in-memory #data object attributes as params within the redirect. You then recreate this object in the index page or wherever you wish to redirect to.
To expand on Matt's answer, the reason you're getting NilClass errors is because:
You're redirecting to a data#show action when no show action has been enabled within your routes file. Since you've set your views up for the index, I'm assuming you want to redirect there when the #data object has been verified as valid:
redirect_to data_path
However I would recommend you follow Rails conventions and specify the data#show route within your routes.rb:
resources :data, only: [:index, :new, :create, :show]
and in your data_controller.rb:
def show
#data = Data.find(params[:id])
end
Another problem is that you're not actually saving the #data object upon creating it. The new method populates the attributes, and valid? runs all the validations within the specified context of your defined model and returns true if no errors are found, false otherwise. You want to do something like:
def create
#data = Data.new(data_params)
if #data.save
redirect_to data_path
else
render :new
end
end
Using save attempts to save the record to the database, and runs a validation check anyways - if validation fails the save command will return false, the record will not be saved, and the new template will be re-rendered. If it is saved properly, the controller will redirect to the index page, where you can call upon the particular data object you want and display it within your view.

HTemplate is missing in rails 3.2

I am trying to create a simple micropost application using rails...
This is my model :
Class Micropost < ActiveRecord::Base
attr_accessible :content, :name
end
Controller:
class MicropostsController < ApplicationController
def create
#blog=Micropost.new( :content => params[:content])
#blog.save
redirect_to microposts_show_path
end
def show
#mblg=Micropost
end
def index
end
end
Views:
create.html.erb
<h1>Microblogs#create</h1>
<p></p>
<%= label_tag(:content) %><br/>
<%= text_field_tag (:content) %><br/>
<%= submit_tag("submit") %><br/>
index.html.erb
<h1>Microblogs#index</h1>
<p>Find me in app/views/microblogs/index.html.erb</p>
show.html.erb
<h1>Microblogs#show</h1>
<p></p>
<%= #mblg.each.do |variable|%>
<p><%= variable.content %></p>
<%end%>
Routes.rb
Blog::Application.routes.draw do
get "microposts/create"
get "microposts/show"
get "microposts/index"
end
i am getting a template missing error... this is a fairly simple application...can you please point out where i am going wrong?
The RESTful controller in Rails has hidden actions (create, update, destroy)
The controller (if created as part of the scaffold) will have four actions visible to the user
index
new
show
edit
In our routes file, you can call
resources :microposts
which Rails will understand and create the routes for a RESTful controller.
Instead of /microposts/create you would use /microposts/new
A good example you can look at is a scaffold.
Within your Rails root directory, do the following
rails g scaffold foo bar
rake db:migrate
You will see that this creates a Foo controller and allows you to new/index/edit/show on this controller. The field that you would be entering and populating is bar.
Once you are finished playing around with this, you can do
rails d scaffold foo
rake db:rollback

undefined method ..._index_path Ruby on Rails

I am trying to get a basic form to work and am struggling because I keep getting the error
undefined method `profiles_index_path' for #<#<Class:0x4fe1ba8>:0x4fccda0>
I have checked through and can't seem to work out where I am going wrong.
In my view (new.html.erb) I have:
<%= form_for #profile do |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>
<%= f.text_field :country %>
<%= f.text_field :about %>
<%= f.submit "Create Profile" %>
<% end %>
In my profiles controller I have:
class ProfilesController < ApplicationController
def new
#title = "New Profile"
#profile = Profiles.new
end
def create
#user = current_user
#profile = #user.profiles.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => "Welcome to your new profile!"
else
render "profiles#new"
end
end
def edit
#user = current_user
#profile = #user.profiles.find(params[:id])
end
def update
#title = "Update Profile"
#user = current_user
#profile = #user.profiles.find(params[:id])
if #profile.update_attributes(params[:profile])
redirect_to profile_path
else
render action: "edit"
end
end
def index
#user = current_user
#profile = #user.profiles.all
#title = "Profile"
end
end
And finally in my profiles model I have
class Profiles < ActiveRecord::Base
belongs_to :user
end
Any help people can offer really would be much appreciated because I am stumped. :)
Sorry forgot to include routes:
controller :profiles do
get "newprofile" => "profiles#new"
get "updateprofile" => "profiles#update"
get "profile" => "profiles#home"
end
resources :profiles, :controller => 'profiles'
The problem is indeed the way you've pluralized your model name. Don't do that. It should be a Profile, not a Profiles. There my be some work around to allow you to use a plural model name, but the answer is to stick to Rails convention rather than fighting the framework. Rename your model to Profile and the url_for helpers will understand how to correctly turn a new Profile object into a /profiles URL.
If you run "rake routes" command, do "profiles_index" appear in your routes? Usually for the index page of a model, the work 'index' is left out so the route is profiles_path
You error probably comes from a view where you've used profiles_index_path instead of profiles_path
I think it's failing due to the convention not being followed with your model name.
So I think you're problem is mostly around that you aren't following the convention on the model name, which would classically be singular, since each instance represents one profile. I think the form_for helper is trying to figure out what to do with it and failing as a result. So you have two options to try and resolve. Refactor the model name to singular (I'm not clear exacly how difficult that would be) or pass the :url paramater to form_for so it knows where to post to.
<% form_for #profile, :url => path_to_create_action do |f| %>
more information here:
I'm working with Rails 5 and I got the same error and it was specific using the word Media as my model and RoR used Medium as the plural so I got different routes when executing rake routes.
What I did to fix it was:
Delete the model I just have created.
rails d scaffold Media
Edit config/initializers/inflections.rb with:
ActiveSupport::Inflector.inflections(:en) do |inflect|
# Here you can put the singular and plural form you expect
inflect.irregular 'media', 'medias'
end
Now execute the scaffold again:
rails g scaffold Media
Now you must have everything in the way you expected. Because you have overwritten the Pluralizations and Singularizations (Inflections) in Ruby on Rails.
I hope it could be useful.
Have you tried to replace your form_for tag with the following?
<%= form_for #profile, :as => :post do |f| %>
It looks like it's trying to treat it as a GET request to "/profile". And, since it is not finding the index action, it craps out. I think forcing it to do a POST will fix this issue.

Resources