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
Related
I know this question has been asked a lot but none of the other solutions worked for me. I have created a scaffold called Properties and have not changed any of the code for it, when I click on the automatically generated link to create a new property, it throws the error message in the title, specifically targeting my def set_property in my properties_controller. I have already created a default scaffold for Users which worked perfectly, which is why I am very confused.
I am on rails v 5.0.2 and ruby v 2.3.3
My Routes.rb:
Rails.application.routes.draw do
get 'sessions/create'
get 'sessions/destroy'
get 'users/about'
resources :users
resources :properties
get 'admin' => 'admin#index'
controller :sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end
root 'users#home'
end
My properties_controller.rb
class PropertiesController < ApplicationController
before_action :set_property, only: [:show, :edit, :update, :destroy, :new]
# GET /properties
# GET /properties.json
def index
#properties = Property.all
end
# GET /properties/1
# GET /properties/1.json
def show
end
# GET /properties/new
def new
#property = Property.new
end
# GET /properties/1/edit
def edit
end
# POST /properties
# POST /properties.json
def create
#property = Property.new(property_params)
respond_to do |format|
if #property.save
format.html { redirect_to #property, notice: 'Property was successfully created.' }
format.json { render :show, status: :created, location: #property }
else
format.html { render :new }
format.json { render json: #property.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /properties/1
# PATCH/PUT /properties/1.json
def update
respond_to do |format|
if #property.update(property_params)
format.html { redirect_to #property, notice: 'Property was successfully updated.' }
format.json { render :show, status: :ok, location: #property }
else
format.html { render :edit }
format.json { render json: #property.errors, status: :unprocessable_entity }
end
end
end
# DELETE /properties/1
# DELETE /properties/1.json
def destroy
#property.destroy
respond_to do |format|
format.html { redirect_to properties_url, notice: 'Property was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_property
#property = Property.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def property_params
params.require(:property).permit(:name, :price, :bed, :bath, :car, :inspect)
end
end
The link I press to get the message:
<%= link_to 'New Property', new_property_path %>
New property page:
<h1>New Property</h1>
<%= render 'form', property: #property %>
<%= link_to 'Back', properties_path %>
and the form that this page renders:
<%= form_for(property) do |f| %>
<% if property.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(property.errors.count, "error") %> prohibited this property from being saved:</h2>
<ul>
<% property.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :price %>
<%= f.number_field :price %>
</div>
<div class="field">
<%= f.label :bed %>
<%= f.number_field :bed %>
</div>
<div class="field">
<%= f.label :bath %>
<%= f.number_field :bath %>
</div>
<div class="field">
<%= f.label :car %>
<%= f.number_field :car %>
</div>
<div class="field">
<%= f.label :inspect %>
<%= f.text_field :inspect %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Remove :new from before_action :set_property:
before_action :set_property, only: [:show, :edit, :update, :destroy]
set_property searches for an id attribute in the params hash and then sets the #property with the property (record from the db) that matches that id, but with new you don't want to search for an existing property, you are creating a new one. So thats why new method sets #property with Property.new:
# GET /properties/new
def new
#property = Property.new
end
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
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])
I have a rails form to collect information on people for a family tree application. There are two drop down boxes that are used to assign the parents of the person being edited/created, however when a selection is made in either, or both, of these boxes, it is not committed to the database. It doesn't throw any exceptions, however when I check the database, the fatherID and motherID fields remain as null.
Here is the complete code for the form:
Does anybody have any ideas where I'm going astray?
Thanks.
<%= form_for(#person) do |f| %>
<% if #person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% #person.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :FirstName %><br>
<%= f.text_field :FirstName %>
</div>
<div class="field">
<%= f.label :LastName %><br>
<%= f.text_field :LastName %>
</div>
<div class="field">
<%= f.label :MaidenName %><br>
<%= f.text_field :MaidenName %>
</div>
<div class="field">
<%= f.label :Sex %><br>
<%= f.select(:Sex, options_for_select([['Male', 'M'], ['Female', 'F']]))%>
</div>
<div class="field">
<p>Parents:</p>
Mother: <%= select(:motherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
Father: <%= select(:fatherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller code
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render action: 'show', status: :created, location: #person }
else
format.html { render action: 'new' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex)
end
end
Model Code
class Person < ActiveRecord::Base
has_ancestry
end
:motherID and :fatherID need to be in params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex) otherwise the controller does not pass these values to the model for them to be saved.
For more information about strong parameters, see the rails guide: http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
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]