Routing Error uninitialized constant SubmitsController (Trying to upload document using Carrierwave) - ruby-on-rails

I am building my first useful Rails application for a teacher to post assignments and students to upload their work (jpeg|pdf) on the website using Carrierwave.
Tutorial I want to replicate: http://www.tutorialspoint.com/ruby-on-rails/rails-file-uploading.htm
Error: "`undefined method submits_path' for #<#:0x007f7260dbc7a0> Did you mean? submit_path"
Error message: Extracted source (around line #14):
13 <div class = "well">
14 <%= form_for #submits, html: { multipart: true } do |f| %>
15 <%= f.label :name %>
16 <%= f.text_field :name %>
17 <%= f.label :attachment %>
model: submit.rb
class Submit < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader # Tells rails to use this uploader for this model.
validates :name, presence: true # Make sure the owner's name is present.
end
controller: submit_controller.rb
class SubmitController < ApplicationController
def index
#submits = Submit.all
end
def new
#submit = Submit.new
end
def create
#submit = Submit.new(submit_params)
if #submit.save
redirect_to submits_path, notice: "The assignment #{#submit.name} has been uploaded."
else
render "new"
end
end
def destroy
#submit = Submit.find(params[:id])
#submit.destroy
redirect_to submits_path, notice: "The assignment #{#submit.name} has been deleted."
end
private
def submit_params
params.require(:submit).permit(:name, :attachment)
end
end
routes:
Rails.application.routes.draw do
resources :submit, only: [:index, :new, :create, :destroy]
get 'welcome/index'
get 'welcome/about'
root 'welcome#index'
end
schema:
ActiveRecord::Schema.define(version: 20160903040246) do
create_table "submits", force: :cascade do |t|
t.string "name"
t.string "attachment"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
rake routes :
Prefix Verb URI Pattern Controller#Action
submit_index GET /submit(.:format) submit#index
POST /submit(.:format) submit#create
new_submit GET /submit/new(.:format) submit#new
submit DELETE /submit/:id(.:format) submit#destroy
welcome_index GET /welcome/index(.:format) welcome#index
welcome_about GET /welcome/about(.:format) welcome#about
root GET / welcome#index
Thanks in advance to all the wonderful people here who are willing to lend a helping hand

You're using #submits insted of #submit, here:
<%= form_for #submits, html: { multipart: true } do |f| %>
Shoul be:
<%= form_for #submit, html: { multipart: true } do |f| %>
Which is the variable you have created in the controller, here:
def new
#submit = Submit.new
end
EDITED ANSWER
I'm gonna take a step back here and point some problems you're facing due to Rails Convention.
The Rails philosophy is Convention Over Configuration. That means that if you follow some conventions, Rails will be able to do what you expect it to do it without configuring anything (or almost anything).
Besides the error I pointed above, all the other errors you have listed in the answers are because you created your controller in the singular SubmitController instead of SubmitsController. This changes the convention expected by Rails, so you would have to some configurations by hand.
Since you're following a tutorial or something, my advice is to take a step back and re-create your controller with the right conventions.

Related

Rials Routing Error:Because of Controller name different from model name?

everyone! I am new to rails and working on Codecademy tutorials. But I wanted to see if I can run the same app on my mac using VS Code and got into some roadblocks. The application is basically to create a form that takes in messages and displays it (in the index view). I wanted to explore changing the names of controller and model to what I want and guess I messed up the internal routing. Following is the controller (messagec)
class MessagecController < ApplicationController
def index
#messages1 = MessagesMo1.all
end
def new
#messages2 = MessagesMo1.new
end
def create
#messages2 = MessagesMo1.new(message_params)
if #messages2.save #tells if the object is saved successfully in db or not
flash[:success] = "Great! Your post has been created!"
redirect_to '/messages'
else
flash.now[:error] = "Fix your mistakes, please."
render 'new'
end
end
private
def message_params
params.require(:message).permit(:content)
end
end
THe following is the model (messagesmo1)
class CreateMessagesMo1s < ActiveRecord::Migration[6.0]
def change
create_table :messages_mo1s do |t|
t.text :content
t.timestamps
end
end
end
The following is the routes.rb file
get '/messages' => 'messagec#index'
get '/messages/new' => 'messagec#new'
post 'messages' => 'messagec#create'
post 'messages_mo1s' => 'message_mo1s#create'
The following is the code in create.html.erb file
<%= form_for(#messages2) do |f| %>
<div class = "field">
<%= f.label :message %><br>
<%= f.text_area :content %>
</div>
<div class = "actions">
<%= f.submit "Create" %>
</div>
<% end %>
I am able to see the message list and able to go to create new message page. But when I submit the form, I am getting the following Routing error:
uninitialized constant MessageMo1sController Did you mean? MessagecController MessagesMController
My first questions is:
1) What am I missing in the routes.rb file?
2) Is there any rule between naming the model similar to that of the controller?
I just replicated all of the above, I think there are many things to keep in mind.
Your model file must be of name messagesmo1.rb and in this model:
class MessagesMo1 < ApplicationRecord
end
Your controller file should be of name messagec_controller.rb and in it:
def index
#messages1 = MessagesMo1.all
end
def new
#messages2 = MessagesMo1.new
end
def create
#messages2 = MessagesMo1.new(message_params)
if #messages2.save #tells if the object is saved successfully in db or not
flash[:success] = "Great! Your post has been created!"
redirect_to '/messages'
else
flash.now[:error] = "Fix your mistakes, please."
redirect_to '/messages/new'
end
end
private
def message_params
params.require(:messages_mo1).permit(:content)
end
In the above point, look at the message_params part, it must be :messages_mo1 and not :message
No changes required in _form.html.erb file
Your migration file must be of name timestamp__create_messages_mo1s.rb and it must have:
class CreateMessagesMo1s < ActiveRecord::Migration[6.0]
def change
create_table :messages_mo1s do |t|
t.text :content
t.timestamps
end
end
end
In your routes.rb file, change the last route:
get '/messages' => 'messagec#index'
get '/messages/new' => 'messagec#new'
post 'messages' => 'messagec#create'
post 'messages_mo1s' => 'messagec#create'
Make sure all your links are updated in index.html.erb, in show.html.erb and in new.html.erb -> Like links to show, delete, edit etc. Or if your just testing remove these links.
After making above changes, run rails db:drop db:create db:migrate as it will clean your DB of old migration.
That's it, now everything should work. The main problem is naming convention should be standard across all files. So it's better to use standard convention.
It finally worked. Following are the 2 changes:
1) Instead of <%= form_for(#messages2) do |f| %>, I used a URL parameter
<%= form_for(#messages2, url:'/messages/') do |f| %>
2)As #cdadityang mentioned, I updated the params to params.require(:messages_mo1).permit(:content)
without the URL being given explicitly, I think the rails is assuming '/message_mo1' are the path. So the URL is basically taking it to 'messagec#create'

Rails form_for results in POST instead of PUT when trying to edit

I am using Rails 4 and have the following error.
Routing Error
No route matches [POST] "/logs/1/meals/13/edit
I’m passing form_for the model object using :meal and the edit page is rendering correctly. However, Rails does not seem to be checking whether or not the meal object has already been saved, so it keeps trying to send the form to the #create action and tries make a POST request instead of sending the form to the update action and making a PUT request when I hit submit.
How do I get the form_for to recognize that I am trying to update an existing object and that PUT is needed instead of POST? Everything else is working and I’ve run all of my migrations. I’m pretty new to Rails, and I’ve spent almost all day trying to figure this out on my own. Please help!
And just to note, when I tried to pass in the model object as #meal.log instead of :meal, Rails was no longer able to recognize :calorie_estimate or :meal_description. Passing the model object as #meal.log left me with a no method error.
meals/edit.html.erb
<h3> EDIT MEAL </h3>
<%= form_for(:meal) do |f| %>
<div id="meal-form">
<%= f.text_field :calorie_estimate, class: 'meal-form-fields', :placeholder => "Calorie Estimate" %>
<%= f.text_field :meal_description, class: 'meal-form-fields', :placeholder => "Food Description" %>
<div class="submit-form" style="width: 75px; height: 15px;">
<%= f.submit 'UPDATE', :class => 'submit-form-text' %>
</div>
</div>
<% end %>
meals_controller.rb
class MealsController < ApplicationController
include MealsHelper
def create
#meal = Meal.new(meal_params)
#meal.log_id = params[:log_id]
#meal.save
redirect_to log_path(#meal.log)
end
def edit
#meal = Meal.find(params[:id])
end
def update
#meal = Meal.find(params[:id])
#meal.update(meal_params)
redirect_to log_path(#log)
end
def meal_params
params.require(:meal).permit(:calorie_estimate, :meal_description)
end
end
possible routes:
Prefix Verb URI Pattern Controller#Action
root GET / logs#index
log_meals GET /logs/:log_id/meals(.:format) meals#index
POST /logs/:log_id/meals(.:format) meals#create
new_log_meal GET /logs/:log_id/meals/new(.:format) meals#new
edit_log_meal GET /logs/:log_id/meals/:id/edit(.:format) meals#edit
log_meal GET /logs/:log_id/meals/:id(.:format) meals#show
PATCH /logs/:log_id/meals/:id(.:format) meals#update
PUT /logs/:log_id/meals/:id(.:format) meals#update
DELETE /logs/:log_id/meals/:id(.:format) meals#destroy
logs GET /logs(.:format) logs#index
POST /logs(.:format) logs#create
new_log GET /logs/new(.:format) logs#new
edit_log GET /logs/:id/edit(.:format) logs#edit
log GET /logs/:id(.:format) logs#show
PATCH /logs/:id(.:format) logs#update
PUT /logs/:id(.:format) logs#update
DELETE /logs/:id(.:format) logs#destroy
routes.rb
Rails.application.routes.draw do
root to: 'logs#index'
resources :logs do
resources :meals
end
end
schema.rb
ActiveRecord::Schema.define(version: 20160128205351) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "logs", force: :cascade do |t|
t.string "entry_date"
t.integer "calorie_goal"
t.string "notes"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "meals", force: :cascade do |t|
t.integer "calorie_estimate"
t.string "meal_description"
t.integer "log_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end
The issue is that you're using nested resources, hence you're confused about which #objects to pass to your form_for.
#app/views/meals/edit.html.erb
<%= form_for [#log, #meal] do |f| %>
As you have it presently, passing :meal is ambiguous - Rails cannot discern the route / method to send its submission to, as it doesn't have that data available.
If you wanted to update an object, you'll have to pass the appropriate data to the form, including the object's id:
<%= form_for :meal, url: { controller: "meals", action: "update", id: "5" }, method: :put do |f| %>
Such as Rails is object orientated, you'll be best passing the actual object to your form_for:
<%= form_for #meal ...
--
The issue you have is that you have a nested resource:
resources :logs do
resources :meals #-> url.com/logs/:log_id/meals/:id
end
This means you need to pass both the Log and Meal values to your form:
#app/controllers/meals_controller.rb
class MealsController < ApplicationController
def edit
#log = Log.find params[:log_id]
#meal = Meal.find params[:id]
end
def update
#log = Log.find params[:log_id]
#meal = Meal.find params[:id]
#meal.update meal_params
end
end
#app/views/meals/edit.html.erb
<%= form_for [#log, #meal] do |f| %>
If your controller is creating an instance variable called #meal you should use that instead of the symbol. So write:
form_for #meal do |f|
and then rails can query the instance variable to see whether it is a new_record? (in which case it will POST the data) or an existing record (in which it will b e a PATCH most likely).
To build a nested route, you will need to set an instance variable #log (I do not see that in your code, but you probably do that already), and then you can write:
form_for [#log, #meal] do |f|
which will calculate the correct path.
The error you get:
Routing Error
No route matches [POST] "/logs/1/meals/13/edit
indicates that your form does a POST instead of a PUT.
To make this work, just add method: :put to the form_for declaration:
<%= form_for(:meal, method: :put) do |f| %>

how to add / route advertisements into posts and comments on a web application in the form of sponsored links?

Very new to programming and ruby on rails, working on a CRUD exercise in an app tutorial. The application has posts and comments that are showing properly. The next task is to add native advertising to the posts and comments through sponsored links. Posts and comments are working on the application, but since I created the Advertisement Model I have been experiencing the following routing errors. Thank you for your help:)
In OS X Terminal:
$ rake db:seed
rake aborted!
ActiveModel::MissingAttributeError: can't write unknown attribute post_id
local.3000 server error:
Started GET "/advertisements" for ::1 at 2015-03-06 20:51:12 -0700
ActionController::RoutingError (uninitialized constant AdvertisementsController):
***advertisement_controller.rb
class AdvertisementsController < ApplicationController
def index
#advertisements = Advertisement.all
end
def show
#advertisement = Advertisement.find(params[:id])
end
end
***advertisement.rb
class Advertisement < ActiveRecord::Base
belongs_to :post
belongs_to :comment
end
***index.html.erb — advertisement
<h1>All Advertisements/h1>
<% #advertisments.each do |advertisment| %>
<div class="media">
<div class="media-body">
<h4 class="media-heading">
<%= link_to advertisment.title, advertisment %>
</h4>
</div>
</div>
<%end%>
***show.html.erb — advertisement
<h1><%= #advertisement.title %></h1>
<p><%= #advertisement.copy %></p>
***routes.rb
Rails.application.routes.draw do
resources :advertisements
resources :posts
get 'about' => 'welcome#about'
root to: 'welcome#index'
***create_advertisements.rb
class CreateAdvertisements < ActiveRecord::Migration
def change
create_table :advertisements do |t|
t.string :title
t.text :copy
t.integer :price
t.timestamps null: false
end
end
end
***seeds.rb
require 'faker'
#Create Posts
50.times do
Post.create!(
title: Faker::Lorem.sentence,
body: Faker::Lorem.paragraph
)
end
posts = Post.all
#Create Comments
100.times do
Comment.create!(
post: posts.sample,
body: Faker::Lorem.paragraph
)
end
#Create Advertisements
15.times do
Advertisement.create!(
post: posts.sample,
body: Faker::Commerce.product_name,
title: Faker::Hacker.say_something_smart,
copy: Faker::Lorem.sentence(3, true),
price: Faker::Commerce.price
)
end
puts "Seed finished"
puts "#{Post.count} posts created"
puts "#{Comment.count} comments created"
puts "#{Advertisement.count} advertisements created"
Looks like you're missing a few columns in your Advertisements table migration. Aside from the timestamps, you're creating three columns: :title, :copy, and :price; however, in your seeds.rb file you're "faking" Advertisements with two missing columns: :post and :body.
Since Advertisements belong_to Posts and Comments you want to make sure to add post_id and comment_id as integers in your advertisements table.
After you've added those columns, including the :post and :body (if you want them as well), run rake db:migrate and then try rake db:seed.

Rails: How to access attributes of my #results object

Having tried to access the 'answer1' attribute on my #results object via:
#results.answer1
...I looked online, and tried the solutions suggested here...
get attribute of ActiveRecord object by string
..but I can't seem to access the attributes of my passed ActiveRecord #results object.
Initially the user is directed to the /quizzes/new view, the QuizzesController#new action which looks like this:
def new
#user = current_user
#quiz_answer = current_user.quiz_answers.build
end
#quiz_answer is, therefore accessible to the view and passed into the form_for there. EDIT: Here is my form (a partial rendered as part of quizzes/new.html.erb):
<%= form_for(#quiz_answer) do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%= f.check_box(:answer2) %>
<%= f.check_box(:answer3) %>
<%= f.check_box(:answer4) %>
<%= f.check_box(:answer5) %>
<%= f.check_box(:answer6) %>
<%= f.check_box(:answer7) %>
<%= f.check_box(:answer8) %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
When the user clicks submit on the form the QuizAnswers#create action is triggered which redirects to results_path (the index action in the ResultsController).
#results is therefore accessible to the view because of the index action in ResultsController:
def index
# in order to access all the results in our view...
#results = current_user.quiz_answers
end
In my results/index view, this
<p><%= #results %></p>
outputs the following to the page:
#<QuizAnswer::ActiveRecord_Associations_CollectionProxy:0x5191b30>
...so the object is not nil.
But when I try to access the 'answer1' attribute of #results, via:
<p><%= #results[answer1] %></p>
OR
<p><%= #results.read_attribute(answer1) %></p>
...I get the following error:
undefined local variable or method `answer1' for #<#<Class:0x72384d8>:0x71b6d10>
Finally, in my routes.rb, I define the following reources:
resources :quizzes
resources :results
resources :quiz_answers
resources :users do
resources :posts
end
But when I include 'resources :quiz_answers' as part of 'resources :user' (immediately below the 'resources :posts' line) I get the following error:
undefined method `quiz_answers_path' for #<#<Class:0x5310618>:0x5411b80>
...when I go to the quizzes/new page.
So my question is: If quiz_answers needs to be a resource included as part of the user resource, how do I pass current_user.quiz_answers to form_for? And if it DOESN'T need to be 'part of' the user resource, how do I access the attributes of quiz_answers?
Once again, if there's anything I'm presuming or doing wrong, please feel free to explain the 'Rails way' of doing it.
EDIT
I think I've been asked for the models, controllers and migration, so here you go:
users controller:
class UsersController < ApplicationController
def show
#user = current_user
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update_attributes(user_params)
if #user.save
redirect_to(#user)
else
render 'edit'
end
end
private
# Using a private method to encapsulate the permissible parameters is just a good pattern
# since you'll be able to reuse the same permit list between create and update. Also, you
# can specialize this method with per-user checking of permissible attributes.
def user_params
params.require(:user).permit(:name, :age, :email, :section)
end
end
quiz answers controller:
class QuizAnswersController < ApplicationController
def new
#user = current_user
#quiz_answer = current_user.quiz_answers.build
end
def create
redirect_to results_path
end
private
def post_params
params.require(:quiz_answer).permit(:body, :user_id)
end
end
results controller:
class ResultsController < ApplicationController
def index
# in order to access all the results in our view...
#results = current_user.quiz_answers
end
end
schema.rb (let me know if this is what you need, migration-wise):
ActiveRecord::Schema.define(version: 20141002130233) do
create_table "posts", force: true do |t|
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
create_table "quiz_answers", force: true do |t|
t.integer "user_id"
t.string "answer1"
t.string "answer2"
t.string "answer3"
t.string "answer4"
t.string "answer5"
t.string "answer6"
t.string "answer7"
t.string "answer8"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "quiz_answers", ["user_id"], name: "index_quiz_answers_on_user_id"
# Could not dump table "users" because of following NoMethodError
# undefined method `[]' for nil:NilClass
end
And the QuizAnswer model:
class QuizAnswer < ActiveRecord::Base
belongs_to :user
end
The User model is pretty long, but it DOES include:
has_many :posts
has_many :quiz_answers
I hope that helps!
All of the comments are perfectly valid i.e. you are setting an CollectionProxy to the variable #results but your main issue is that the create action in your QuizAnswersController does nothing except redirect to results_path.
Although Rails will do a lot of work for you, you have to process the parameters which are submitted by your form in the create action.
There's quite a lot in issue with your code here so I'd suggest you read this part of the Rails Guide on Action Controller. You'll also need to adjust the post_params method in your QuizAnswersController as you only permit the body and user_id attributes to be mass-assigned meaning you won't be able to do anything with the answer1 etc. attributes unless you assign them manually.
Having said that, what do they do in the form? As far as I can see, they will just be checkboxes setting a true or false value?
Your QuizAnswersController needs to look something like this.
class QuizAnswersController < ApplicationController
...
def create
#quiz_answer = current_user.quiz_answers.new(post_params) #from private method
if #quiz_answer.save
redirect_to results_path
else
#error handle here
end
end
private
def post_params
params.require(:quiz_answer).permit(:answer1, :answer2) #add other attributes here
end
end
EDIT: You say you are permitting a body attribute on the QuizAnswer model but that's not one of its attributes according to your DB schema so I've updated the code.
Since #results is a relation that includes all quiz_answers that belong to the current user:
#results = current_user.quiz_answers
your results/index.erb view will contain something like:
<%- #results.each do |quiz_answer| %>
<%# ... some code shows answer data like %>
<h4>Quiz Answer</h4>
<p><%= quiz_answer.answer1 %></p>
<p><%= quiz_answer.answer2 %></p>
<p><%= quiz_answer.answer3 %></p>
<p><%= quiz_answer.answer4 %></p>
<p><%= quiz_answer.answer5 %></p>
<p><%= quiz_answer.answer6 %></p>
<p><%= quiz_answer.answer7 %></p>
<p><%= quiz_answer.answer8 %></p>
<%- end %>
If no quiz_answers are assigned to the current user, that form will be skipped in output. And probably you should add name field to quiz_answer table then you can add it to above form as:
<p>Name: <%= quiz_answer.name %></p>
To assign the newly created quiz_answer add to create action inside the QuizAnswersController assignment to the current user, like follows:
class QuizAnswersController < ApplicationController
def create
quiz_answer = QuizAnswer.create(params.require(:quiz_answer).permit(:answer1)
current_user.quiz_answers << quiz_answer
redirect_to results_path
# require 'pry'
# binding.pry
end
end
After the quiz_answer.save! please make sure that the current_user.quiz_answers isn't empty by checking its #size. You can debug your it by using pry gem. Just add it to Gemfile, then insert to required place as a breakpoint, and uncomment the two lines with require, and binding.

ActiveRecord::RecordNotFound in Controller#destroy

I'm trying to get the controller's "destroy" to work correctly and I'm wondering what the correct set up should be.
The error that I'm getting is
ActiveRecord::RecordNotFound in AuthenticationsController#destroy
Couldn't find Authentication without an ID
My controller looks like
class AuthenticationsController < InheritedResources::Base
def destroy
#authentication = current_user.authentications.find(params[:id])
#authentication.destroy
redirect_to(:back)
end
database table
create_table "authentications", :force => true do |t|
t.integer "user_id"
t.string "provider"
t.string "uid"
t.string "secret"
t.string "token"
end
I have tried other parameters such as :user_id
How can I get users to destroy their tokens? (with the option to re-authenticate later)
You're not passing id to controller
try
<%= link_to "Disconnect Your Authentication", {:controller=>'authentications', :action=>'destroy', :id=>current_user.authentication_id} %>
or use path helper with #autentication argument as option.
(You will need to edit your routes file)
If you're wanting to destroy all authentications for a user, you could certainly change your controller's destroy method to be:
def destroy
current_user.authentications.destroy_all
end
A more conventional approach would be to destroy a particular authentication. In that case the link_to method needs a path that includes an id parameter (which will end up as your params[:id] value in the controller). You can imagine a view snippet like the following that displays all a user's authentications, each with a destroy link:
<ul>
<% current_user.authentications.each do |a| %>
<li>
<%= a.provider %>
-
<%= link_to 'Disconnect Your Authentication', authentication_path(a), :method => :delete %>
</li>
<% end %>
</ul>
This assumes current_user is a helper and that your routes are set up on your authentication model. The authentication_path helper uses the a authentication instance to generate a path, complete with an id parameter.

Resources