Ruby on Rails: Data not saving ActiveRecord - ruby-on-rails

I'm pretty new to Ruby on Rails and I've been trying to develop a simple blog. However when I try to save the new Post, the page reloads a new page and no data is saved. The data however is present in the URI.
Here's my controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :category, :body)
end
end
I modified the form produced by scaffolding:
<form role="form">
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :title %><br>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :category %><br>
<%= f.select(:category, options_for_select(["Programming", "Commentary", "Book Reviews"]), {}, { class: "form-control" })%>
</div>
<div class="form-group">
<%= f.label :body %><br>
<%= f.text_area :body, class: "form-control", rows: "50" %>
</div>
<div class="actions">
<%= f.submit(class: "btn btn-primary") %>
</div>
<% end %>
</form>
Here's my model:
class Post < ActiveRecord::Base
validates :title, presence: true
end
Here's the logs from the server:
Started GET "/posts/new? utf8=%E2%9C%93&authenticity_token=QfJgH82nuYVTEa1vovO4VlIjZmMeJvBLj6bkNKDrz08%3D&post%5Btitle% 5D=Hello&post%5Bcategory%5D=Programming&post%5Bbody%5D=Hello&commit=Create+Post" for 127.0.0.1 at 2014-08-11 11:38:46 -0400
Processing by PostsController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"QfJgH82nuYVTEa1vovO4VlIjZmMeJvBLj6bkNKDrz08=", "post"=> {"title"=>"Hello", "category"=>"Programming", "body"=>"Hello"}, "commit"=>"Create Post"}
Rendered posts/_form.html.erb (2.3ms)
Rendered posts/new.html.erb within layouts/application (3.2ms)
Completed 200 OK in 21ms (Views: 19.1ms | ActiveRecord: 0.0ms)

Your problem is from your invalid HTML - you have an outer <form> tag, and then an inner <form> tag (generated by the Rails form_for). Your browser is following the directive of the outer form, which by default is just to submit to the same page via a GET request.
You want your browser to follow the inner form tag, which is telling the browser to submit a POST request to the create URL. So remove the outer form tag.

Related

Please review the problems below: Rails created post

I dont't know why but when i'm trying to create post, i got this error.
I created a scaffold "post"
Then i wanted to get my posts in a different controller, in my Controller home.
I put "belongs_to :home" in my Post.rb
In this step, all is fine.
But when i'm trying to create post, i got this "Please review the problems below:"
Processing by PostsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"0QgNSnhZWnsa+U9iYi1RB2Yk+qoW1be0Mj/o3579Es74oKBD452HQxZF144KBhR+in7UaSf9OLpzAyn8aJrB6A==", "post"=>{"title"=>"sfsf", "content"=>"sdfsfsfs", "author"=>"sdfsfsdf"}, "commit"=>"Create Post"} (0.4ms) BEGIN (0.3ms) ROLLBACK Rendering posts/new.html.erb within layouts/application Rendered posts/new.html.erb within layouts/application (14.6ms) User Load (0.7ms) SELECT users. FROM users WHERE users.id = 2 ORDER BY users.id ASC LIMIT 1 Rendered layouts/_header.html.erb (6.8ms) Rendered layouts/_footer.html.erb (0.9ms) Completed 200 OK in 1512ms (Views: 381.2ms | ActiveRecord: 1.4ms)*
post_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all.order("created_at DESC")
end
# GET /posts/1
# GET /posts/1.json
def show
#posts
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html {redirect_to #post, notice: 'Article crée.'}
format.json {render :show, status: :created, location: #post}
else
format.html {render :new}
format.json {render json: #post.errors, status: :unprocessable_entity}
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html {redirect_to #post, notice: 'Article édité.'}
format.json {render :show, status: :ok, location: #post}
else
format.html {render :edit}
format.json {render json: #post.errors, status: :unprocessable_entity}
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html {redirect_to posts_url, notice: 'Article supprimé.'}
format.json {head :no_content}
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :content, :author)
end
end
post/new.html.erb
<div class="container left-box">
<h1 class="left-box-title">Ajouter un article</h1>
<%= simple_form_for #post, wrapper: :vertical_form do |f| %>
<%= f.error_notification %>
<%= f.input :title, label: 'Titre' %>
<p>Contenu</p>
<%= f.text_area :content, class: 'col-md-12 form-control content_post_create' %>
<%= f.input :author, label: 'Auteur' %>
<%= f.button :submit, class: "btn-primary", label: 'Mettre en ligne' %>
<%= f.button :button, "Recommencer", type: "reset", class: "btn-outline-secondary" %>
<% end %>
<%= link_to "Retour à l'accueil", posts_path %>
</div>
Your error comes from belongs_to :home in Post.rb:
The belongs_to association creates a one-to-one match with another
model. In database terms, this association says that this class
contains the foreign key. (source)
If you add the error full messages in your form like this:
<%= simple_form_for #post, wrapper: :vertical_form do |f| %>
<ul>
<% #post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
...
<% end %>
you should see this error: Home must exist
To fix your issue you can remove the belongs_to association or, if Home is really a model, add the home_id to #post in your create action before saving.

Rails nomethod error

I'm new to Rails and am trying to create an application that takes a user request. However this is what is happening when I am trying to create a new request.
Request Controller:
class RequestsController < ApplicationController
before_action :set_request, only: [:show, :edit, :update, :destroy]
# GET /requests
# GET /requests.json
def index
#requests = Request.all
end
# GET /requests/1
# GET /requests/1.json
def show
end
# GET /requests/new
def new
#request = Request.new
end
# GET /requests/1/edit
def edit
end
# POST /requests
# POST /requests.json
def create
#request = Request.new(request_params)
respond_to do |format|
if #request.save # <-------------- The problem is here
format.html { redirect_to #request, notice: 'Request was successfully created.' }
format.json { render :show, status: :created, location: #request }
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /requests/1
# PATCH/PUT /requests/1.json
def update
respond_to do |format|
if #request.update(request_params)
format.html { redirect_to #request, notice: 'Request was successfully updated.' }
format.json { render :show, status: :ok, location: #request }
else
format.html { render :edit }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
# DELETE /requests/1
# DELETE /requests/1.json
def destroy
#request.destroy
respond_to do |format|
format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_request
#request = Request.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def request_params
params.require(:request).permit(:user_id, :description, :created)
end
end
The error says there is no "Create" method in the requests controller, however the method that is saying this is the create method. I think that a problem is that my view isn't passing the description as a parameter and I'm not sure how to do that/why it's not already.
_form.html.erb (Rendered by edit.html.erb):
%= form_for(#request) do |f| %>
<% if #request.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#request.errors.count, "error") %> prohibited this request from being saved:</h2>
<ul>
<% #request.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<center>
<div class="field">
<%= f.label 'Describe your favor' %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
</center>
<% end %>
If someone could show me how to pass the description object as a parameter to my create method and get the method to not crash.
Here is the error log:
NoMethodError (undefined method `Request' for #<Request:0x007f9fbd8992e8>):
app/controllers/requests_controller.rb:32:in `block in create'
app/controllers/requests_controller.rb:31:in `create'
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_source.erb (6.9ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.8ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.9ms)
Rendered /usr/local/rvm/gems/ruby-2.2.2/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (29.4ms)
Using Request (or Response) as the name of a model is not a very good idea since you will end up shadowing the request object. Which is a core part of Rails controllers.
It will also make it very confusing to reason about your code since it will collide with a core concept in MVC and web development in general.
Use a thesaurus and find another name for your model.

Rails Instance Variables

I'm working on creating a survey app where surveys can have many questions and questions can have many surveys. What I'd like to do is on the survey show page display a button "Add new question" that allows a user to add a new question to that survey. So in my code I send the survey id like this:
<%= link_to "Add Question", new_question_path(:survey_id => #survey.id)%>
Then I can set #survey using the params I'm sending in my question controller. This is working fine in my :new method, but is throwing a nil error when I try to call in the :create method. I believe this is because a new instance of the controller is getting created which no longer has access to the :survey_id param I sent initially.
So I'm wondering if there is anyway to pass along the params to the next instance of the controller? Or is there a better way to send which survey should be set for that question? Is this something I could "save" in a hidden field? I thought about trying to save something in my model, but to save a question earlier would require me to remove the validations I have.
Here's my question_controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
before_action :set_survey, only: [:new, :create]
# GET /questions
# GET /questions.json
def index
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
#answers = #question.answers
end
# GET /questions/new
def new
#question = Question.new
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
respond_to do |format|
if #question.save
#survey.questions << #question
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', status: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, status: :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, status: :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
def set_survey
#survey = Survey.find(params[:survey_id])
flash[:alert] = "Survey is " + #survey.to_s
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :single_response, :surveys, :surveytizations)
end
end
And the form I'm creating the question with:
<%= form_for(#question) 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 %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :single_response %><br>
<%= f.check_box :single_response %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Thanks! Any help is very much appreciated!
UPDATE:
I was able to work using Rails.cache.write/Rails.cache.read - How to pass values between controller methods
Is there anything wrong with doing it that way or is that the best route?
I think you need to store the survey_id in a hidden field. Then you can access it from the questions controller. In your view:
<%= form_for(#question) do |f| %>
<%= f.hidden_field :survey_id %>
#rest of form
You also might have to change your new action to something like this:
#question = Question.new(:survey_id => params[:survey_id])
If the questions always belongs to a survey it could be a good idea to nest the routes so that you always can check which survey you are working on.

Ruby on Rails form_for reference class id and pass to child comment

I have a class called "questions", which is similar to an article, and each of them can have comments. Now the problem is, that I want to show multiple questions on the index page and all displaying the comments of the specific question as well as a small little form to leave a comment, which should be added to its question. Basically I have added the form and done everything, apart from figuring out how to get the question id and pass it to the comment.
I have made a little screenshot as well: http://prntscr.com/2pjk0i
questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#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
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
#current_user ||= User.find_by_id(session[:user_id])
#question.update(:user_id => #current_user.id)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', status: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, status: :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, status: :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, :body)
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
#current_user ||= User.find_by_id(session[:user_id])
#comment.update(:user_id => #current_user.id, :question_id => ?) # What to add here to get the specific question id?
respond_to do |format|
if #comment.save
format.html { redirect_to '/', notice: 'comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to '', notice: 'comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to '' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:title, :body)
end
end
index.html.erb
<h1>Listing questions</h1>
<%= link_to 'New Question', new_question_path %>
<hr>
<% #questions.each do |question| %>
<!-- Author -->
<%= question.user.name %> <br>
<!-- Date -->
<%= question.created_at %> <br>
<!-- Title -->
<%= question.title %> <br>
<!-- Body -->
<%= question.body %> <br>
<%= question.id %> <br>
<!-- Comment count -->
<%= question.comments.size %> Comment <br>
<!-- Comments -->
<% question.comments.each do |comment| %>
<!-- Comment Author -->
<%= comment.user.name %> <br>
<!-- Comment Date -->
<%= comment.created_at %> <br>
<!-- Comment Body -->
<%= comment.body %> <br>
<% end %>
<%= form_for(question.comments.new) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<hr>
<% end %>
Thank you in advance for your help! :)
The form_for will need to submit the question_id somehow - either by a route or through the form. I recommend a route.
If you don't interact with comments independently - if there is always a question, then change your routes to something like this:
resources :questions do
resources :comments
end
Then - in your form for, you will do this
<%= form_for [question, question.comments.new] do |f| %>
This will cause the form to submit (POST) to /question/:question_id/comments and you can handle it from there.
In the comments controller - you'll get the question from the params[:question_id] and return the result via an ajax response (respond to json).
This part is still tricky if you haven't done it before. If you need help with that part, you can probably find good examples or ask a separate question...
you can add hidden field inside your form
<%= f.hidden_field :question_id, value: question.id %>
or you can change your form
<%= form_for :comment, :url => comments_path(question_id:question.id) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
when u submit this form u will have url like /comments?question_id=id

Rails posts scaffold not parsing html

I'm trying to learn rails, and am using my blog as an excuse to do so.
Right now, I'm playing around with the posts scaffold. I get the MVC and the idea behind it, so I was about to recreate it, when I ran accross the following error.
If I enter content like
text
text
text
in the 'content' tag of posts form, It displays all the text as one block.
text text text
I thought I could try doing something like
<p>text</p>
<p>text</p>
<p>text</p>
but, it shows
<p>text</p><p>text</p><p>text</p>
What I'd like Rails to do is to actually parse the html in content. What would I do to get that to happen?
Here's the New Form Partial, which I used to submit the content
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here's the Posts Controller as a whole
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
#posts = Post.paginate(page: params[:page])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
# GET /posts/1
# GET /posts/1.json
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
end
To prevent XSS attacks Rails escapes html by default. If you don't want your html escaped you have to use .html_safe on the string you don't want escaped. In show.html.erb:
<%= #post.content.html_safe %>
Or a better way would be not to enter <p>'s in your content field and use simple_format to do the formatting into paragraphs, like this:
<%= simple_format(#post.content) %>
Of course you could also use a combination of both. E.g. when you have omitted paragraph tags, but do have links in your content:
<%= simple_format(#post.content.html_safe) %>
Note that you can safely use .html_safe on content you entered yourself, but don't use it on content that is entered by third parties (like comments) for that would open up your site to XSS attacks.
Mischa's answer led me down a rabbit hole of searching, and I also found this gem -- https://github.com/spohlenz/tinymce-rails
It adds TinyMCE, a wysiwig editor to a textarea

Resources