I am fairly new to Ruby. I am trying to follow along with a tutorial for creating a simple posting app.
My create action will not work. I tried this and it seems to do something in the terminal, but it doesn't add it to my Posts object.
Here is my posts controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
#post = Post.new(:title => params[:title], :content => params[:content])
#post.save
end
def edit
end
def update
end
def destroy
end
end
Here is my new view:
<h1>Add a New Post</h1>
<%= form_for #post do |f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :content %>
<%= f.text_area :content %>
</p>
<p>
<%= f.submit "Add a New Post" %>
</p>
<% end %>
This is what comes up in the terminal when I try to submit:
Started POST "/posts" for ::1 at 2016-08-31 17:54:39 -0700
ActiveRecord::SchemaMigration Load (16.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tGpevHtpEoP5jHYqCn1G7tUKX9YWnx+PWkqlPzKadTCiIEX1UGs96mSCrDf UIShKjp+ObwNA6G1nh3KE5gAIgw==", "post"=>{"title"=>"Jack's Post", "content"=>"Please use this post"}, "commit"=>"Add a New Post"}
(0.1ms) begin transaction
SQL (16.0ms) INSERT INTO "posts" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2016-09-01 00:54:40 UTC], ["updated_at", 2016-09-01 00:54:40 UTC]]
(14.7ms) commit transaction
No template found for PostsController#create, rendering head :no_content
Completed 204 No Content in 114ms (ActiveRecord: 31.3ms)
I feel like I've read about a million stack overflow posts about this and no one seems to have the answer. Any help would be very appreciated!
You've successfully inserted a record into the database. What do you want to happen next? How about:
redirect_to action: 'index'
You should use strong params to get the parameters you need from the form.
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
#post.save
end
private
def post_params
params.require(:post).permit(:title, :content)
# params.require(:post).permit! # Allow all
end
end
If you want your exisiting solution to work, you would need to prefix the params like this:
#post = Post.new(:title => params[:post][:title], :content => params[:post][:content])
If you examine the logs, you'll see the form input is nested inside of post
"post"=>{"title"=>"Jack's Post", "content"=>"Please use this post"}
When you look in the logs it clearly says that I have rendered no view.
No template found for PostsController#create, rendering head :no_content
So in PostsController#create action we need to redirect to any action, mostly we redirect to show action. So you need add following line in create action.
# redirects user to show page of newly created post.
if #post.save
redirect_to #post
else
render 'new'
end
Go kill waves :)
Related
I am following a guide to build a blog with rails, simple Post model with title and body.
I am using simple form and upon form submission to create a new post, the post saves created_at and updated_at values, but not the actual content submitted in the form.
I have attempted removing the code for simple form and using Rails native form_for. This DOES save all values to the database. I am new to simple form, not certain whether or not I am using it correctly.
Here is the console record:
Started POST "/posts" for ::1 at 2019-08-17 13:51:01 -0500
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"qY8kYZxVIMBL8lzHYuQ4qOu6nXsTGLWCRhLPJ2eiAU8EyzR61fZppAFBYmgcm3rx02FYAHcCgFBVlUyDTLtDGA==", "post"=>{"title"=>"Simple Form Test", "body"=>"<p>Test Test Test</p>\r\n"}, "commit"=>"Create Post"}
(0.0ms) begin transaction
SQL (3.3ms) INSERT INTO "posts" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2019-08-17 18:51:01.325736"], ["updated_at", "2019- 08-17 18:51:01.325736"]]
(7.7ms) commit transaction
Redirected to http://localhost:3000/posts/3
Completed 302 Found in 28ms (ActiveRecord: 11.1ms)
Here is the form:
<%= simple_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="form-group">
<%= f.input :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.input :body, :as => :ckeditor, input_html: {:ckeditor => {:toolbar => 'FULL'}}, class: "form-control" %>
</div>
<div class="form-group">
<%= f.button :submit %>
</div>
<% end %>
Here is the controller:
class PostsController < ApplicationController
before_action :find_post, only: [:edit, :update, :show, :delete]
# Index action to render all posts
def index
#posts = Post.all
end
# New action for creating post
def new
#post = Post.new
end
# Create action saves the post into database
def create
#post = Post.new
if #post.save(post_params)
flash[:notice] = "Successfully created post!"
redirect_to post_path(#post)
else
flash[:alert] = "Error creating new post!"
render :new
end
end
# Edit action retrives the post and renders the edit page
def edit
end
# Update action updates the post with the new information
def update
if #post.update_attributes(post_params)
flash[:notice] = "Successfully updated post!"
redirect_to post_path(#post)
else
flash[:alert] = "Error updating post!"
render :edit
end
end
# The show action renders the individual post after retrieving the the id
def show
end
# The destroy action removes the post permanently from the database
def destroy
if #post.destroy
flash[:notice] = "Successfully deleted post!"
redirect_to posts_path
else
flash[:alert] = "Error updating post!"
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def find_post
#post = Post.find(params[:id])
end
end
Hopin
g to be able to create posts with body and title, and learn more about simple form.
Thanks in advance!
You wrote #post = Post.new without pass your parameters to your object, so when you save you object you save an empty object.
It should be either :
#post = Post.new(post_params)
Or directly
#post = Post.create(post_params)
Rails 5.1.6
I've got an app where products are listed and you can add a quantity of a product to an order. Well, that's the idea anyway. So, right now I've got a form to grab the quantity and also grab the product id and the order id to associate them through the order_items table which also holds the quantity. It looks like the form is grabbing the order_id and setting it in the order_items parameter. In this case, 5. Order with id 5 does exist in the db. When the params are passed to .new however, it's passing a blank id? What am I missing here?
ActiveRecord::RecordNotFound (Couldn't find Order with 'id'=): < wha?where'd the id go?
Form ERB
<% #products.each do |product| %>
<div class="col s4">
<h4><%= link_to product.name, product_path(product) %></h4>
<%= form_for #order_item do |f| %>
<%= f.hidden_field :order_id, value: #order.id %>
<%= f.hidden_field :product_id, value: product.id %>
<%= f.number_field :quantity, placeholder: "quantity" %>
<span class="waves-effect waves-light btn"><%= f.submit "Add to order" %></span>
<% end %>
</div>
class OrderItemsController < ApplicationController
def create
#order = Order.find(params[:id])
#item = #order.order_items.new(item_params)
#order.save
if #order.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
def item_params
params.require(:order_item).permit(:quantity, :product_id, :order_id)
end
Terminal
Started POST "/order_items" for 127.0.0.1 at 2018-06-06 16:50:31 -0700
Processing by OrderItemsController#create as JS
Parameters: {"utf8"=>"✓", "order_item"=>{"order_id"=>"5",
"product_id"=>"2", "quantity"=>""}, "commit"=>"Add to order"}
Order Load (0.2ms) SELECT "orders".* FROM "orders" WHERE
"orders"."id" = $1 LIMIT $2 [["id", nil], ["LIMIT", 1]]
Completed 404 Not Found in 2ms (ActiveRecord: 0.2ms)
ActiveRecord::RecordNotFound (Couldn't find Order with 'id'=):
app/controllers/order_items_controller.rb:4:in `create'
There are at least three things wrong with your :create action:
1) One of the hidden fields in your form passes the order_id in as a param, you should use that to find the order like so:
#order = Order.find(params[:order_item][:order_id])
2) You call save twice on the #order instance in the :create action.
3) You are actually calling save on the #order instance variable, but at no point do you save the #item instance variable. Is #item saved when #order is saved?
So I'd try the following:
def create
#order = Order.find(params[:order_item][:order_id])
# how come you don't save this? You instantiate it but don't appear to call save at any point.
#item = #order.order_items.new(item_params)
# remove the following line, which I've commented out:
# #order.save
# Consider whether you wish to save #order or #item, or both
if #order.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
Hope it helps, good luck
Here:
#order = Order.find(params[:id])
You're finding by params[:id]. But look!
Parameters: {"utf8"=>"✓", "order_item"=>{"order_id"=>"5", "product_id"=>"2", "quantity"=>""}, "commit"=>"Add to order"}
No params[:id]. You do, however, have params[:order_item][:order_id]. Perhaps you intended to use that?
Also, you can simplify your create action:
def create
#order_item = OrderItem.new(item_params)
if #order_item.save
flash[:notice] = "Your order has been added!"
redirect_to orders_path
else
render :new
end
end
Given that you have all the order_item attributes in your parameters:
"order_item"=>{"order_id"=>"5", "product_id"=>"2", "quantity"=>""}
There's no real need to find #order (unless you're feeling all belt and suspenders about things).
I'm building a rails 4.2.0 app with a contact us page (this page does have a semi-empty controller). I'm trying to embed a form partial from another controller.
Here is the code (minus the text):
<% if user_signed_in? %>
<% render 'enquiries/form' %>
<% end %>
When I run this I get the error 'First argument in form cannot contain nil or be empty'.
My enquiries form looks like a basic rails form:
<%= form_for #enquiry do |f| %>
<% if #enquiry.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#enquiry.errors.count, "error") %> prohibited this enquiry from being saved:</h2>
<ul>
<% #enquiry.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :subject, "Subject:" %><br>
<%= f.text_field :subject %>
</div>
<div class="field">
<%= f.label :e_description, "Description:" %><br>
<%= f.text_area :e_description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
What could be the possible reason for the error? Or is there a better way of embedding a view into another?
Update/Edit:
Here's the routes:
devise_for :users
resources :rooms do
resources :viewings
end
resources :rmcats
resources :extras
resources :extracats
resources :enquiries
root :to => redirect('/pages/home')
get 'pages/home'
get 'pages/contactus'
And the enquiry controller:
class EnquiriesController < ApplicationController
before_action :set_enquiry, only: [:show, :edit, :update, :destroy]
# GET /enquiries
def index
#enquiries = Enquiry.all
end
# GET /enquiries/1
def show
end
# GET /enquiries/new
def new
#enquiry = Enquiry.new
end
# GET /enquiries/1/edit
def edit
end
# POST /enquiries
def create
#enquiry = Enquiry.new(enquiry_params)
if #enquiry.save
redirect_to #enquiry, notice: 'Enquiry was successfully created.'
else
render :new
end
end
# PATCH/PUT /enquiries/1
def update
if #enquiry.update(enquiry_params)
redirect_to #enquiry, notice: 'Enquiry was successfully updated.'
else
render :edit
end
end
# DELETE /enquiries/1
def destroy
#enquiry.destroy
redirect_to enquiries_url, notice: 'Enquiry was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_enquiry
#enquiry = Enquiry.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def enquiry_params
params.require(:enquiry).permit(:subject, :e_description)
end
end
This is the pages controller:
class PagesController < ApplicationController
around_filter :resource_not_found
# def home
# end
private
# If resource not found redirect to root and flash error.
# => For pages this will rarely be needed as it should 404.
def resource_not_found
yield
rescue ActiveRecord::RecordNotFound
redirect_to root_url, :notice => "Page not found."
end
end
Edit:
Log:
Started GET "/pages/contactus" for ::1 at 2015-03-21 01:05:25 +0000
Processing by EnquiriesController#new as HTML
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Rendered enquiries/_form.html.erb (0.0ms)
Rendered pages/contactus.html.erb within layouts/application (0.0ms)
Completed 200 OK in 235ms (Views: 234.6ms | ActiveRecord: 0.0ms)
It is telling you that #enquiry is nil at the time it is trying to render the form. You need to call the new action to create the #enqiury for the form to represent.
You could change your route to:
get 'pages/contactus' => 'enquiries#new'
Then in your Enquiry controller:
def new
#enquiry = Enquiry.new
render 'pages/contactus'
end
EDIT:
Ok, so now we combine what Friends Systems put in his answer:
<% if user_signed_in? %>
<%= render 'enquiries/form' enquiry: #enquiry %>
<% end %>
And now change any instance of #enquiry in the form to enquiry
This is because you need to pass the variable to the partial.
the problem is, that your #enquiry variable is not defined in the context you are rendering the partial.
its not defined by the controller action that gets called, you should create a instance of Enquiry by calling
#enquiry = Enquiry.new
in your action.
In Addition
to use it somewhere else i would pass the #enquiry instance variable as a locale variable to the partial
<% render 'enquiries/form', :enquiry => #enquiry %>
your form method should then look like this:
<%= form_for enquiry do |f| %>
...
<% end %>
of course all the instances vars should be replaced then. just remove the '#'
EDIT:
According to your controller setup you posted above the best way would be to use something like
#enquiry ||= Enquiry.new
in your form partial to make shure a new instance is created if #enquiry is nil.
I'm a long time lurker who's google-fu is failing him today. I've been learning to use Rails using a video series that was created before Rails 4 came out. As such, the lectures use the attr_accessibly mass assignments. I've been attempting to convert this to working strong parameters, but am having an issue actually saving info to my PostgreSQL database.
Basically, I should go to localhost:3000/new, add a title, body, and category, then submit. This goes off without a hitch, but my /posts (which lists all posts) shows the title as /posts/(whatever row number it's on), does not display the text, and only shows a date-time stamp when clicking on the post (url). Also, my database is only storing a post/row number.
Note: I am aware of things like ActiveAdmin, but would prefer to learn how to make/save posts manually before using such modules.
Here is the post controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
#category = Category.all
end
def create
#post = Post.create(post_params)
if #post.save
redirect_to posts_path, :notice => "Your post has been saved"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
private
def post_params
params.require(:post).permit(:title, :body, :category_id, :author_id)
end
end
Here is the html form:
<h1>Add New Post</h1>
<%= form_for #post do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %><br />
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %><br />
</p>
<p>
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {:include_blank=> "Select One"}%><br />
</p>
<p>
<%= f.submit "Add Post" %>
</p>
<% end %>
And finally, the posts.rb file:
class Post < ActiveRecord::Base
# Deprecated
# attr_accessible :title, :body, :category_id, :author_id
belongs_to :category
accepts_nested_attributes_for :category
end
I am no Ruby expert, so my first thought is that the .save method requires additional arguments when using strong_parameters. Adding (post_params) to the save method didn't seem to have an effect, and I haven't been able to determine my issue using the Ruby documentation. I'd prefer to do this the "right" way, as opposed to just using the protected_attributes gem to use a deprecated (seemingly less secure) method.
Thanks in advance for any assistance you may be able to offer. When I get rich, I'll buy you a Ferrari*.
*May or may not be a Hot Wheels replica.
Eidt 2: Here is what the server throws out when attempting to POST to my database. It mentions a mass assignment error, but I thought I wasn't using them (strong params instead). Pardon my newbiness:
Started POST "/posts" for 127.0.0.1 at 2015-03-11 18:28:13 -0700
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9Ybchogw5u+sYbZOFYZtbJbXBkWC5EuCIZNUmAKyAQI=", "post"=> {"title"=>"blahblahblah", "body"=>"blahblahblah", "category_id"=>"1"}, "commit"=>"Add Post"}
WARNING: Can't mass-assign protected attributes for Post: title, body, category_id
app/controllers/posts_controller.rb:18:in `create'
[1m[36m (0.0ms)[0m [1mBEGIN[0m
[1m[35mSQL (1.0ms)[0m INSERT INTO "posts" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2015-03-12 01:28:13.990971"], ["updated_at", "2015-03-12 01:28:13.990971"]]
[1m[36m (2.0ms)[0m [1mCOMMIT[0m
[1m[35m (0.0ms)[0m BEGIN
[1m[36m (0.0ms)[0m [1mCOMMIT[0m
Redirected to http://localhost:3000/posts
Completed 302 Found in 10ms (ActiveRecord: 3.0ms)
And the index view. This is a training exercise, so it's just text, no styling:
<h1>Blog Posts</h1>
<% #posts.each do |post| %>
<h3><%= link_to post.title, post %></h3>
<p><%= post.body %></p>
<% end %>
uncomment your request/permit line in post_params and actually add the param names into it
def post_params
params.require(:post).permit(:title, :body, :category_id, :author_id)
end
That is why you are getting no data in your posts - because you aren't getting any data out of params anymore.
If the permit/require line is causing a different bug for you - we will help you fix that, but commenting out the security measure is not the way to solve it.
Latest
I have switched to Simple form. No problem with permitting date attributes there.
Recent attempts
I have put a demo repository on Github illustrating the problem:
This one uses formtastic and displays my problem with:
Unpermitted parameters: date_of_receipt(1i), date_of_receipt(2i), date_of_receipt(3i), date_of_receipt(i)
https://github.com/bigos/permit_date_selector/commit/9f142b79c51e71dca35c988125a2912b83b91972
This one doesn't use formtastic and works fine;
https://github.com/bigos/permit_date_selector/commit/4c53b934ac5cd3f04241bf462e7b677ef5d28335
Initial post
When I try to submit my form I get this message
Unpermitted parameters: date_of_receipt(i)
I have :date_of_receipt in the list of permitted parameters.
My form input selecting the date looks as follows:
<%= f.input :date_of_receipt, as: :date_select %>
Should I give up on formtastic and go back to standard forms?
I've created a fresh Rails app (using Rails 4.1.5 and Formtastic 2.3.1) to try to replicate, and I can't, so I'm closing. Here's what I had:
# Migration
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :body
t.datetime :published_at
t.timestamps
end
end
end
# Model
class Post < ActiveRecord::Base
end
# Controller
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render :new
end
end
def show
#post = Post.find(params[:id])
end
protected
def post_params
params[:post].permit(:title, :body, :published_at)
end
end
# View
<%= semantic_form_for #post do |f| %>
<%= f.inputs do %>
<%= f.input :title %>
<%= f.input :body %>
<%= f.input :published_at %>
<% end %>
<%= f.actions do %>
<%= f.action :submit %>
<% end %>
<% end %>
By simply permitting :published_at, I was able to successfully save a Post into the database with the time I had selected. Here's the development.log:
Started POST "/posts" for 127.0.0.1 at 2014-09-06 21:13:37 +1000
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Jv4Pd7aNgvjkCtzrX+gHNeCNfX3L8t6IpEOEAWzdeIo=", "post"=>{"title"=>"sdfgs", "body"=>"sdgfdfg", "published_at(1i)"=>"2019", "published_at(2i)"=>"1", "published_at(3i)"=>"1", "published_at(4i)"=>"00", "published_at(5i)"=>"01"}, "commit"=>"Create Post"}
(0.1ms) begin transaction
SQL (0.2ms) INSERT INTO "posts" ("body", "created_at", "published_at", "title", "updated_at") VALUES (?, ?, ?, ?, ?) [["body", "sdgfdfg"], ["created_at", "2014-09-06 11:13:37.685160"], ["published_at", "2019-01-01 00:01:00 .000000"], ["title", "sdfgs"], ["updated_at", "2014-09-06 11:13:37.685160"]]
(8.8ms) commit transaction
Redirected to http://localhost:3000/posts/3
Completed 302 Found in 12ms (ActiveRecord: 9.1ms)
There's no extra trickery required, this is how you do it :)
When you inspect the element on the page, you will see three different elements for date_select.
model[date_of_receipt(1i)], model[date_of_receipt(2i)], model[date_of_receipt(3i)]
So you will have to permit
date_of_receipt(1i), date_of_receipt(2i), date_of_receipt(3i)
in your controller