In my Rails app I'm trying to create a form for updating model instance attributes with new info and am running into trouble.
When I hit submit on the edit form, the following error is thrown:
param is missing or the value is empty: product
And here's the code snippet it provides:
# all the attributes that must be submitted for the product to be listed
def product_params
params.require(:product).permit(:name, :price, :description)
end
end
I think the problem is that the model :product isn't getting passed from the edit form to the update action. Here's the form:
<h1>Edit your listing</h1>
<%= form_for edit_item_path(#product), url: {action: "update"} do |f| %>
<div><%= f.label :name %><br />
<%= f.text_field :name, :placeholder => "Name yourself" %>
</div>
<div><%= f.label :price %><br />
<%= f.number_field :price, :placeholder => "Name your price" %>
</div><br />
<div><%= f.label :description %><br />
<%= f.text_area :description, :cols => "50", :rows => "10", :placeholder => "Write a few sentences about the item you're listing. Is it in good condition? Are there any accessories included?"%>
</div>
<br />
<%= f.submit "Update listing" %>
<% end %>
Here are the edit and update actions in my products_controller:
def edit
#product = Product.find(params[:id])
end
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(product_params)
format.html {render :action => "show"}
else
format.html {render :action => "edit"}
end
end
end
Finally, my product routes
get "/products/new(.:format)" => "products#new", :as => "list_item"
post "/products/create(.:format)" => "products#create"
get "/products(.:format)" => "products#index"
get "/products/:id(.:format)" => "products#show"
get "/products/:id/edit(.:format)" => "products#edit", :as => "edit_item"
post "/products/:id/update(.:format)" => "products#update"
So anyone know what the problem is? Am I not passing the right info to the update action? If I'm not, what do I need to do to do it?
form_for
The problem you have is you're using form_for without any object
form_for generates an appropriate form tag and yields a form builder
object that knows the model the form is about. Input fields are
created by calling methods defined on the form builder, which means
they are able to generate the appropriate names and default values
corresponding to the model attributes, as well as convenient IDs, et
form_for helpers are primarily designed to give you a way to manage ActiveRecord objects:
<%= form_for #object do |f| %>
...
<% end %>
--
Fix
Everything inside this form block will have to work with the object in the form_for. As you have only used a path helper in your form_for method, it's not going to work as you hope.
You'll need to do this:
<%= form_for #product, url: {action: "update"} do |f| %>
This will ensure your form_for populates the object correctly. The error you have basically says your strong_params method is expecting this structure:
params => {
"product" => {
"name" => ____,
"price" => _____,
"description" => ______
}
}
As you've not included the #product object in your form_for, your params hash won't have the product key, thus causing your error. The fix is to populate the form_for element correctly
Replace
form_for edit_item_path(#product), url: {action: "update"}
with
form_for #product
which is similar to
form_for #product, as: :product, url: product_path(#product), method: :patch do |f|
Related
I am Rails newbie. I am creating a section that is pulling existing user's details and when the user click on edit, he can save the changes he has made. However, the changes aren't reflecting once the user saves it. Can you tell me what I am missing in here?
Here's the html/ruby form I am using:
<%= form_tag(html: {:id => 'user_profile_form'}, :url => patient_profile_path(#user), :method => :put) do %>
<%= text_field_tag(:inputFieldName, "#{#user.first_name} #{#user.last_name}", {:disabled => true}) %>
<%= submit_tag 'Save', :id=> 'saveButton' %>
<%= end %>
Here's the routes:
put :patient_profile, to: 'users#patient_profile'
post :dashboard, to: 'dashboard#index'
Here are the controller codes:
def patient_profile
if params[:user]
u = params[:user]
#user.first_name = u[:first_name] unless u[:first_name].nil? || u[:first_name].empty?
#user.last_name = u[:last_name] unless u[:last_name].nil? || u[:last_name].empty?
#user.save!
# index
render :index
end
end
It doesn't look like your form is actually updating anything since your form fields don't match your model. Try simplifying your form action:
View
<%= form_for(#user, html: {:id => 'user_profile_form'}, :url => patient_profile_path(#user), :method => :put) do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.submit "Update User" %>
<%= end %>
Controller:
def patient_profile
# TODO: Handle failed validation
#user.update_attributes!(params[:user])
# index
render :index
end
end
def user_params
params.require(:user).permit(:first_name, :last_name)
end
I have a form that creates a Post. A Post has a non-required field called school_id. On the Post form (to create a new Post) I have a checkbox. If that checkbox is checked, I want to set :school_id to equal the school_id that's also set to current_user (object created by Devise). How can I set the Post.school_id to equal current_user.school_id if the checkbox is checked?
The checkbox I have on the form is passing a :school_id of 1 and never changes. Is this because checkboxes can only accept boolean values of either 1 or 0? Here's what I have on the form so far:
<%= simple_form_for #post do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_area :content, required: true %>
<% if #school %>
<%= f.label :school_id, "Set school",:class => "checkbox inline" %>
<%= f.check_box :school_id, :value => current_user.school.id %>
<% end %>
<%= f.submit "Submit Post", class: 'btn btn-primary' %>
<% end %>
EDIT
post controller
def create
#school = current_user.school
#post = current_user.posts.build(params[:post])
#post.school_id = current_user.school_id if #school && #post.use_school.present?
end
controller with the post form
def index
#post = current_user.posts.build
#school = current_user.school
#post.school_id = current_user.school_id if #school && #post.use_school.present?
respond_to do |format|
format.html # index.html.erb
format.json
format.js
end
end
Your problem comes from Simpleform! Simpleform forces checkbox input to be a boolean. You'll have the same problem with other syntaxes:
<%= f.input :school_id, :as => :boolean, :input_html => { :value => current_user.school.id } %>
To go deeper:
<%= f.check_box :school_id, :value => current_user.school.id %>
will generate something like this:
<input type="hidden" name="post[school_id]" value="0">
<input type="checkbox" name="post[school_id]" value="1">
Note: Simpleform automatically adds the first line (a good practice) to be sure that a value (0) is sent on submit when the input is unchecked. Otherwise, you may have issues on model update.
Your field is not a boolean, you shouldn't use a checkbox. Moreover, an user can edit the value of the checkbox (firebug & co) and that may lead to inconsistent datas or hack. So, with a checkbox you should check the school_id is correct in your controller.
I suggest this workarround:
app/views/posts/new.rb:
<% if #school %>
<%= f.label :use_school, "Set school",:class => "checkbox inline" %>
<%= f.input :use_school, :as => :boolean %>
<% end %>
app/models/post.rb:
attr_accessor :use_school
app/controllers/posts_controller.rb:
#post = Post.new(params[:post])
#post.school_id = current_user.school_id if #school && #post.use_school.present?
Note: the controller part may be done directly in your model with a :before_save.
I am new to ruby, trying to follow the official documentation and create a basic form for creating a post:
<%= form_for #post, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :entry, :size => "60x12" %>
<%= f.submit "Create" %>
<% end %>
The form is successfully adding an entry to the database, but an empty one, I think I must be missing something in my controller? Do I need to pass the variables somehow?
def create
#post = Main.create
end
A basic create action can look like this. You first initialize a new post. Depending on if it successfully saves you proceed.
# app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def create
#post = Post.new(params[:post])
if #post.save
redirect_to #post, notice: 'Post has been created.'
else
render :new
end
end
end
You can shorten your form.
<%= form_for #post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.text_area :entry, :size => "60x12" %>
<%= f.submit %>
<% end %>
You can see excellent example code along these lines when you generate a scaffold, so I would encourage you to try $ rails generate scaffold Post title body:text and learn by example.
Submitting a form passes the values entered into that form (along with some other information) to the controller as a hash called "params" - the params will contain a block labelled with the name of the form, in this case "post".
You need to use the post block from params in the creation of the new object.
def create
#post = Main.new(params[:post])
if #post.save
# handles a successful save
else
# handles validation failure
end
end
Try:
#post = Main.new(params[:post])
#post.save
I am working on rails app , In which I have created a table Product Name:string and Number: integer.
The application should give user a form where he can search a product by his number if product exists it should give product name from database.
My search.html.erb is this.
<%= form_for #products, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
<%= f.text_area :number, :size => "60x12" %>
<%= f.submit "Search" %>
<% end
What will be the definition of search Method in ProductController and routes i need to add in routes.rb?
Irrespective of nifty forms, this is how I would have done this:
In config/routes.rb
replace resources :products' with
resources :products do
post 'search', :on => :collection
end
This will give me a search_products_path
In your view:
<%= form_for(:search, :url => search_products_path) do |f| %>
<%= f.text_field :number, :placeholder => "Enter number to search" %>
<%= f.submit "Search" %>
<% end %>
In your products_controller.rb
def search
number = params[:search][:number]
#result = Product.find_by_number(number)
#not_found = true unless #result
end
In your views/products/search.html.erb, use #result to show the product information; take care while checking whether or not the desired product is actually found or not. I have set the boolean #not_found in case it doesn't exist.
In my tickets.js.coffee:
$.ajax '/comments/add',
type: 'POST',
dataType: 'html'
success: ( data ) ->
alert 'success'
<%= form_for #comment, :url => user_ticket_message_comments_path( #user, #ticket, m ), :html => { :class => "add-comment", :id => "add-comment-" + #ticket.id.to_s } do |f| %>
<%= f.label :body, "Add comment" %>
<%= f.text_area :body %>
<%= f.hidden_field :message_id, :value => m.id %>
<%= f.submit "Add comment" %>
<% end %>
Comments table:
id | message_id | body
----------------------
CommentsController:
def create
#comment = params[:comment]
#comment.save
end
My routes.rb:
resources :messages do
resources :comments
end
I get this error:
undefined method `save' for {"body"=>"awef", "message_id"=>"15"}:ActiveSupport::HashWithIndifferentAccess
Comment belongs to a Message and Message has many comments.
Where should I look to fix this error?
params[:comment] is a Hash, not a Comment object, and thus can't be "saved". You need to create a new Comment object and assign each attribute to it, then save the Comment object:
def create
#comment = Comment.new(params[:comment])
#comment.save
end
Depending on how "new" your app is, config.active_record.whitelist_attributes may be set to true, in which case the above will give you a security error and you should read the Rails Guides on Mass-Assignment for more information about how to properly assign attributes (you should actually read it either way).