Building movie review site , user can upload movies but when anyone wants to review the movie by clicking on the write a review button i get errors NoMethodError in Reviews#new . so in my code it goes to the _form reviews.html.erb
_form.reviews.html.erb
<%= form_for([#movie, #review]) do |f| %> - error
<% if #review.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#review.errors.count, "error") %> prohibited this review from being saved:</h2>
<ul>
<% #review.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :rating %><br>
<%= f.number_field :rating %>
</div>
<div class="field">
<%= f.label :comment %><br>
<%= f.text_area :comment %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
review controller.rb
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
before_action :set_movie
before_action :authenticate_user!
respond_to :html
def new
#review = Review.new
respond_with(#review)
end
def edit
end
def create
#review = Review.new(review_params)
#review.user_id = current_user.id
#review.movie_id = #movie.id
if #review.save
redirect_to #movie
else
render 'new'
end
end
def update
#review.update(review_params)
respond_with(#review)
end
def destroy
#review.destroy
respond_with(#review)
end
private
def set_review
#review = Review.find(params[:id])
end
def set_movie
#movies = Movie.find(params[:movie_id])
end
def review_params
params.require(:review).permit(:rating, :comment)
end
end
movie controller
class MoviesController < ApplicationController
before_action :set_movie, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#movies = Movie.all
end
def show
end
def new
#movie = current_user.movies.build
end
# GET /movies/1/edit
def edit
end
# POST /movies
# POST /movies.json
def create
#movie = current_user.movies.build(movie_params)
respond_to do |format|
if #movie.save
format.html { redirect_to #movie, notice: 'Movie was successfully created.' }
format.json { render :show, status: :created, location: #movie }
else
format.html { render :new }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /movies/1
# PATCH/PUT /movies/1.json
def update
respond_to do |format|
if #movie.update(movie_params)
format.html { redirect_to #movie, notice: 'Movie was successfully updated.' }
format.json { render :show, status: :ok, location: #movie }
else
format.html { render :edit }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# DELETE /movies/1
# DELETE /movies/1.json
def destroy
#movie.destroy
respond_to do |format|
format.html { redirect_to movies_url, notice: 'Movie was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_movie
#movie = Movie.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def movie_params
params.require(:movie).permit(:title, :description, :movie_length, :director, :rating, :image)
end
end
rake routes
new_movie_review GET /movies/:movie_id/reviews/new(.:format) reviews#new
NoMethodError in Reviews#new
Showing /Users/neilpatel/Desktop/Rails/movies/app/views/reviews/_form.html.erb where line #1 raised:
undefined method `reviews_path' for #<#<Class:0x007f92db41b548>:0x007f92dd52ff18>
Trace of template inclusion: app/views/reviews/new.html.erb
Rails.root: /Users/neilpatel/Desktop/Rails/movies
Application Trace | Framework Trace | Full Trace
app/views/reviews/_form.html.erb:1:in `_app_views_reviews__form_html_erb__1769795460297873272_70134360199660'
app/views/reviews/new.html.erb:3:in `_app_views_reviews_new_html_erb___894596083071563840_70134360230600'
app/controllers/reviews_controller.rb:11:in `new'
write a review button
<div class="panel panel-default">
<div class="panel-body"></div>
<div class="row">
<div class="col-md-4">
<%= image_tag #movie.image.url(:medium) %>
<div class="table-responsive">
<table class="table">
<tbody></tbody>
<tr>
<td><strong>Title:</strong></td>
<td><%= #movie.title %></td>
</tr>
<tr>
<td><strong>Description:</strong></td>
<td><%= #movie.description %></td>
</tr>
<tr>
<td><strong>Movie Length:</strong></td>
<td><%= #movie.movie_length %></td>
</tr>
<tr>
<td><strong>Director:</strong></td>
<td><%= #movie.director %></td>
</tr>
<tr>
<td><strong>Rating:</strong></td>
<td><%= #movie.rating %></td>
</tr>
</table>
<%= link_to "Write a Review", new_movie_review_path(#movie) %>
</div>
</div>
</div>
<%= link_to 'Edit', edit_movie_path(#movie) %> |
<%= link_to 'Back', movies_path %>
config routes
Rails.application.routes.draw do
devise_for :users
resources :movies do
resources :reviews, except: [:show, :index]
end
root 'movies#index'
end
You have:
#movies = Movie.find(params[:movie_id])
in your set_movie method. You should have:
#movie = Movie.find(params[:movie_id])
Related
I am creating a simple store, I have a single product table. I want anyone accessing the store at url 'website/products' to only be able to 'show' products. but on the url 'website/admins/products' I want to create, edit, destroy.
I have two controllers with the same name 'product_controller'. one is in 'controller/admin' the other is just in 'controller'.
the admin controller has full CRUD while the other controller only has show.
My problem is that I am always routed to the same controller ('website/admins/products' sends me to the 'controller/product_controller')
I am not sure if the problem is in my route file or my form (or something else?)
This is my form that is identical for both
<%= form_with( model: product, local: true) do |form| %>
<% if product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :description %>
<%= form.text_area :description %>
</div>
<div class="field">
<%= form.label :price %>
<%= form.text_field :price %>
</div>
<div class="field">
<%= form.label :inventory_count %>
<%= form.number_field :inventory_count %>
</div>
<div class="admin/actions">
<%= form.submit %>
</div>
And this is my route file
Rails.application.routes.draw do
namespace :admin do
resources :products
end
resources :products
end
Added:
controllers/products_controller
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
def index
#products = Product.all
end
def show
end
def update
respond_to do |format|
if #product.ipdate(product_params)
format.html {redirect_to #product, notice: 'product was successfully updated.' }
else
format.json {render :edit }
format.json {render json: #product.errors, status: :unprocessable_entity }
end
end
end
private
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(:title, :description, :price, :inventory_count)
end
end
controllers/admin/products_controller
class Admin::ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
def index
#products = Product.all
end
def show
end
def new
#product = Product.new
end
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #product.ipdate(product_params)
format.html {redirect_to #product, notice: 'product was successfully updated.' }
else
format.json {render :edit }
format.json {render json: #product.errors, status: :unprocessable_entity }
end
end
end
def destroy
#product.destroy
respond_to do |format|
format.html {redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json {head :no_content }
end
end
private
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(:title, :description, :price, :inventory_count)
end
end
Update: View index.html.erb
24 <p id="notice"><%= notice %></p> 23 22 <h1>Products</h1> 21 20 <table> 19 <thead> 18 <tr> 17 <th>Title</th> 16 <th>Description</th> 15 <th>Price</th> 14 <th>Inventory count</th> 13 <th colspan="3"></th> 12 </tr> 11 </thead> 10 9 <tbody> 8 <% #products.each do |product| %> 7 <tr> 6 <td><%= product.title %></td> 5 <td><%= product.description %></td> 4 <td><%= product.price %></td> 3 <td><%= product.inventory_count %></td> 2 <td><%= link_to 'Show', product %></td> 1 <td><%= link_to 'Edit', edit_admin_product_path(product) %></td> 25 <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td> 1 </tr> 2 <% end %> 3 </tbody> 4 </table> 5 6 <br> 7 8 <%= link_to 'New Product', new_admin_product_path %>
If you have any thoughts or suggestions I would really appreciate it, thanks!
The routes are not the problem, if you run rails routes with that code you can see something like:
admin_products GET /admin/products(.:format) admin/products#index
POST /admin/products(.:format) admin/products#create
new_admin_product GET /admin/products/new(.:format) admin/products#new
edit_admin_product GET /admin/products/:id/edit(.:format) admin/products#edit
admin_product GET /admin/products/:id(.:format) admin/products#show
PATCH /admin/products/:id(.:format) admin/products#update
PUT /admin/products/:id(.:format) admin/products#update
DELETE /admin/products/:id(.:format) admin/products#destroy
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:id/edit(.:format) products#edit
product GET /products/:id(.:format) products#show
PATCH /products/:id(.:format) products#update
PUT /products/:id(.:format) products#update
DELETE /products/:id(.:format) products#destroy
If you want to use different controllers you need two forms that generates routes to those controllers respectively
<%= form_with scope: :product, url: product_path(#product), method: :patch do |form| %>
...
<% end %>
For admin
<%= form_with scope: :product, url: admin_product_path(#product), method: :patch do |form| %>
...
<% end %>
Update
For new products
<%= form_with scope: :product, url: products_path do |form| %>
...
<% end %>
<%= form_with scope: :product, url: admin_products_path do |form| %>
...
<% end %>
Api reference https://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
Everything looks great as far as I can tell -- but the contents for the field_for nested form aren't displaying the 3 question forms I want. Why?
survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
end
question.rb
class Question < ActiveRecord::Base
belongs_to :survey
end
surveys_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
3.times { #survey.questions.build }
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name)
end
end
surveys/new.html.erb
<h1>New Survey</h1>
<%= render 'form' %>
<%= link_to 'Back', surveys_path %>
surveys/_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<% f.fields_for :questions do |builder| %>
<p>
<%= builder.label :content, "Question" %><br />
<%= builder.text_area :content, :rows => 3 %>
</p>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Can't believe I did this -- was missing <%= on fields_for
I get "3 errors prohibited this event from being saved:Title can't be blank Date can't be blank Description can't be blank. it was working perfectly but not sure whats wrong with it now?
When they are not even blank?
here is the controller.
class EventsController < ApplicationController
before_action :authenticate_user!, :only => [:create , :destroy]
before_action :set_event, only: [:show, :edit, :update, :destroy]
# GET /events
# GET /events.json
def index
#events = Event.all
end
# GET /events/1
# GET /events/1.json
def show
end
# GET /events/new
def new
#event = Event.new
end
# GET /events/1/edit
def edit
end
# POST /events
# POST /events.json
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /events/1
# PATCH/PUT /events/1.json
def update
respond_to do |format|
if #event.update(event_params)
format.html { redirect_to #event, notice: 'Event was successfully updated.' }
format.json { render :show, status: :ok, location: #event }
else
format.html { render :edit }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# DELETE /events/1
# DELETE /events/1.json
def destroy
#event.destroy
respond_to do |format|
format.html { redirect_to events_url, notice: 'Event was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_event
#event = Event.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def event_params
params.require(:event).permit(:title, :date, :description)
end
end
Here is the form:
<%= form_for(#event) do |f| %>
<% if #event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% #event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :date %><br>
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
model code as per request :
class Event < ActiveRecord::Base
validates_presence_of :title , :date, :description
validates_uniqueness_of :title
end
Problem was with one of the gems I have installed which I have now removed. working now.
I am fairly new to Rails and I'm creating a question and answers site similar to stackoverflow.
I have created the questions, but I'm not sure about how to now create the answers.
I saw a similar post that had some info on so I tried
rails g resource Answer question_id:integer content:text user_id:integer
I have added in
answer.rb
belongs_to :question
belongs_to :user
question.rb
belongs_to: user
has_many:answers
user.rb
has_many :answers
has_many :questions
In my questions/Show, I have this:
<div class="container">
<div class="row">
<div class="span12">
<h2><%= #question.title %></h2>
</div>
<div class="span6">
Asked by <%= link_to #question.user.full_name %>
</div>
<div class="span5 offset1">
<%= time_ago_in_words(#question.created_at) + " ago" %>
<% if current_user.present? && current_user.id == #question.user_id %>
<%= link_to 'Edit', edit_question_path(#question) %>
<% else %>
<% end %>
</div>
<hr>
<p>Description: <%= #question.description %></p>
<hr>
</div>
<%= render 'answer' %>
</div>
In my questions/_answer.html.erb
<div class="container">
<%= simple_form_for(#question.answer.new, html: {class: "form-horizontal"}) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :content, :input_html => { :class => "span6", :rows => 4 }, label: 'Answer', placeholder: 'Type your answer here'%> %>
<%= f.button :submit, :class => 'btn btn-inverse' %>
<%= link_to (submit_tag 'Cancel', :type => :reset, :class => "btn btn-danger"), root_path %>
<% end %>
</div>
This is my questions_controller.rb
class QuestionsController < ApplicationController
before_filter :authenticate_user!, only: [:new, :create, :edit, :update]
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
#question = Question.new
end
# GET /questions/1/edit
def edit
#question = Question.find(params[:id])
if #question.user == current_user
render :edit
else
flash[:alert] = "You don't have permission to edit this question"
redirect_to root_path
end
end
# POST /questions
# POST /questions.json
def create
#question = current_user.questions.new(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', question: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, question: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #question.errors, question: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :description)
end
end
But i'm not really sure what to write in my answers controller.
I would really appreciate any tips!
Thanks
Maybe try using nested resources to create answers on questions. Similar to comments on articles in blogs.
http://railscasts.com/episodes/139-nested-resources
I know that there are many questions a but every solution that i've tried did not work.
I am trying to create a sign in form, but I am getting the following error
First argument in form cannot contain nil or be empty
replacing #user with User.new will solve the error , but than I can't check for #user.errors.any..
any suggestions?
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset7">
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<br>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
and my controller code is
class UsersController < ApplicationController
before_action :set_user, only: [:show]
def new
#user = User.new
end
# POST /user
# POST /user.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /user/1
# PATCH/PUT /user/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def edit
end
# DELETE /user/1
# DELETE /user/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
In your edit, update and delete actions, you do not set #user.
You should maybe change your before filter:
before_action :set_user, only: [:show, :edit, :update, :destroy]
or
before_action :set_user, except: [:index, :new]