form_for doesn't submit fields to database - ruby-on-rails

I've searched and searched and nothing came up, so I need to ask you guys for help.
I have a simple new form that should take two fields from form_for and then post it into database. The problem is it doesn't.
My sample db has only two fields: name and site_id
Here's my new.html.erb:
<%= form_for #kejsu do |f| %>
<%= f.text_field :name %>
<%= f.text_field :site_id %>
<%= f.submit "Create" %>
<% end %>
Here's the controller:
def new
#kejsu = Kejs.new
end
def create
#kejsu = Kejs.new(params[:kejsu])
if #kejsu.save
redirect_to kejs_index_path
else
render "new"
end
end
After hitting submit button only timestamps are inserted. Here's the snippet from rails server:
Started POST "/cases" for 192.168.56.1 at 2013-12-10 23:11:03 +0000
Processing by KejsyController#create as HTML
Parameters: {"utf8"=>"â", "authenticity_token"=>"Sr2ssiwtRtk9pRT5VfuDFglsEmGnjzwVkRGGBSb2zhA=", "kejs"=> {"name"=>"aa", "site_id"=>"3"}, "commit"=>"Create"}
(0.1ms) begin transaction
SQL (5.1ms) INSERT INTO "kejs" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Tue, 10 Dec 2013 23:11:03 UTC +00:00], ["updated_at", Tue, 10 Dec 2013 23:11:03 UTC +00:00]]
(4.0ms) commit transaction
Redirected to http://192.168.56.101:3000/cases
Completed 302 Found in 14ms (ActiveRecord: 9.2ms)
As you can see those fields are passed as parameters, but INSERT doesn't insert them at all.
I've tried it with default restful routing, writing my own routes and it doesn't work either way.
As a bonus my routes:
get 'cases' => 'kejsy#index', as: :kejs_index
get 'cases/new' => 'kejsy#new', as: :new_kejs
post 'cases' => 'kejsy#create'

Your params[:kejsu] reference uses :kejsu, but your parameters exist under params[:kejs], so you're picking up nil for the value.
The key in params is determined by the class name of the object passed to form_for (i.e. Kejs in this case), not by the variable name (i.e. #kejsu). If you think about it, this makes sense because the variable name is not even available to form_for, since the value of the #kejsu is what is passed.

to debug you can use render :text => params.inspect inside your controller so I will change my code like this
def create
render :text => params.inspect
end
Now go and sumbit your form. What is name of key inside your params? Is it kejsu or kejs?
If its kejs than you can change your code to
def create
#kejsu = Kejs.new(params[:kejs])
if #kejsu.save
redirect_to kejs_index_path
else
render "new"
end
end

As promised, the answer with strong parameters:
def create
#kejsu = Kejs.new(kejs_params)
if #kejsu.save
redirect_to kejs_index_path
else
render "new"
end
end
def kejs_params
params.require(:kejs).permit(:name, :site_id)
end
I needed to change the way I'm dealing with parameters passed via form by creating new method that permits given fields. Now it works like it supposed to.
Thanks for all the hints.

Related

How does rails generate the object from a form submission?

My Controller
class MessagesController < ApplicationController
def index
#messages = Message.all
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if #message.save
redirect_to '/messages'
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:content)
end
end
My corresponding view
<div class="create">
<div class="container">
<%= form_for(#message) do |f| %>
<div class="field">
<%= f.label :message %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
</div>
</div>
I'm a bit confused about how things work under the hood for Rails object creations. Currently doing the Codecademy tutorial, but they've skipped a couple of explanation steps.
When the form submits button is pressed does f.submit generate
a JSON object in a POST request?
After getting routed to the message controllers' create action. How does #message.save know if it's been saved successfully? Isn't it just an object populated by the parameters passed in at this point? Does it route to the DB first before the controller?
You can see what gets submitted by a form submission in your rails server logs. Just run rails server in a terminal, open up your localhost, submit a form and immediately check what gets spit out in the terminal.
You might get something like this:
Started POST "/messages" for ::1 at 2021-10-25 11:41:33 +0200
Processing by MessagesController#create as HTML Parameters: {"message"=>"text", "content"=>"hey"}
[here you will see the SQL run to INSERT new data into the database]
Completed 201 Created in 1ms (ActiveRecord: 2.0ms | Allocations: 2073)
Breaking this down you get 5 pieces of information.
Type of request and endpoint with a timestamp
Controller and format used
Params in JSON
SQL query run if any
Response status with benchmarks for parts used in response, how much time queries took, how much rendering took etc.
save method from rails will try to save an instance of an initialized model into the database and will return true or false depending on the result of the action. There is also save! method that will raise an error if the operation fails, instead of simply returning false boolean value. So to answer your question specifically:
JSON object is sent in params of your POST request, generated based on the HTML form.
#message is an object populated by params (in your case it's only content param that is actually used). Using save on it will prompt ActiveRecord to connect to the database and perform an INSERT action, saving it to the database.
It does not route to the DB first, the controller controls the actions performed based on the request. If something hits the database, you will have to prompt it, as you do by using the save method.
save method in rails documentation

Insert multirows from checkboxes [duplicate]

I am stuck in that although my array parameter is being captured, it fails to insert it into the database. I do not get an unpermitted parameters error or anything. It just fails to recognize the array when inserting to the DB.
What I would like to do: Capture any box that is checked off, and insert the data as separate rows into the database.
Here is what I have:
/subscribe/categories/2
<div>
<%= simple_form_for #subscription do |f| %>
<div class="form-inputs">
<%= f.hidden_field :dashboard_id, value: 1 %>
<%= f.hidden_field :category_id, value: #category.id %>
<%= f.collection_check_boxes :feed_id, Feed.where("category_id = ?", #category), :id, :name %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
</div>
CategoriesController
def show
#subscription = Subscription.new
end
SubscriptionsController
def subscription_params
params.require(:subscription).permit(:dashboard_id, :category_id, :feed_id => [])
end
When submitted, here is the console output:
Processing by SubscriptionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Zw2VkwujDLQjV4krjPF8N1EiYo5L/XOrUwedlHCvwB0=", "subscription"=>{"dashboard_id"=>"1", "category_id"=>"2", "feed_id"=>["3", "4", ""]}, "commit"=>"Create Subscription"}
(0.2ms) BEGIN
SQL (1.6ms) INSERT INTO `subscriptions` (`category_id`, `created_at`, `dashboard_id`, `updated_at`) VALUES (2, '2014-01-06 02:17:41', 1, '2014-01-06 02:17:41')
(116.6ms) COMMIT
Redirected to http://localhost:3000/subscriptions/3
Completed 302 Found in 173ms (ActiveRecord: 119.3ms)
Two questions:
Why is there an extra "" for my feed_id array? (Only 2 possible checkboxes)
Why am I not capturing the array to insert it into the database?
Thanks!
The reason your array is not being inserted into the database is that Active Record currently does not support the Postgresql array type. In order to insert these as separate rows the check-boxes need to be represented as individual instances of a model.
Possibly something like...
Category < ActiveRecord::Base
has_many: feeds
...
end
Feed < ActiveRecord::Base
belongs_to: category
...
end
Now this would also mean that you would need to use the form_tag helper instead of the form_for. This would allow you to create a composite form consisting of multiple individual objects. Inserting this would just mean iterating and inserting over each object; giving you separate rows. Hope this helps.
For anyone that wants to know how to do this, here is one solution I've come up with. Everything in my first post remains the same. In my SubscriptionsController (from which the form is created), here is my create action:
def create
dashboard = params[:subscription][:dashboard_id]
category = params[:subscription][:category_id]
feed = params[:subscription][:feed_id]
#subscription = feed.map { |subscribe| Subscription.create(dashboard_id: dashboard, category_id: category, feed_id: subscribe) }
end
Works as advertised. If anyone thinks for some reason that I am overlooking this is a terrible idea, please comment.

Ruby on rails Common error: Params missing?

I am building a Order management system. I recently posted a problem about adding a order to a customer. It seems that i have fixed it for 99%. if i look in my terminal it first finds the current customer ID and then creates a new order. The following result is.
Customer Load (0.2ms) SELECT "customers".* FROM "customers" WHERE "customers"."id" = ? LIMIT 1 [["id", 111]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "orders" ("customer_id", "created_at", "updated_at") VALUES (?, ?, ?) [["customer_id", 111], ["created_at", "2015-11-12 13:28:21.185604"], ["updated_at", "2015-11-12 13:28:21.185604"]]
(8.2ms) commit transaction
But the problem is, it doesn't add the params. I did this intentionally just to check if my syntax would execute the following sql statement. But once i add params i get a common error "param is missing or the value is empty: order"
Here is my code:
Controller
def createorders
#customer = Customer.find(params[:id]) #find current id??
#current_user = Order.find(params[:id])
#orders = #customer.orders.new(order_params)
if #orders.save
flash[:notice] = "Subject created successfully"
redirect_to(:action => 'index')
else
#If save fails, redisplay the form so user can fix problems
render('new') #het zit in de new.html template
end
end
private
def order_params
#same as using "params[:subject]", expect that it:
# - raises an error if :subject is not present
# - allows listed attributes to be mass-assigned
params.require(:order).permit(:pakket, :verstuurt)
end
end
View
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="subject new">
<h2>Create Subject</h2>
<%= form_for(:order, :url=> {:action => 'createorders'}) do |f| %>
<table summary="subject form fields">
<tr>
<th>pakket</th>
<td><%= f.text_field(:pakket) %></td>
</tr>
<tr>
<th>verstuurt</th>
<td><%= f.text_field(:verstuurt) %></td>
</tr>
</table>
<div class="form-buttons">
<%= submit_tag("Create Subject") %>
</div>
<% end %>
</div>
Error message
ActionController::ParameterMissing in OrderController#createorders
param is missing or the value is empty: order
Extracted source (around line #107):
105
106
107
108
109
110
def order_params
params.require(:order).permit(:pakket, :verstuurt)
end
end
Serverside Log
Started GET "/order/createorders?id=111" for ::1 at 2015-11-13
11:58:30 +0100 Processing by OrderController#createorders as HTML
Parameters: {"id"=>"111"} Customer Load (0.2ms) SELECT
"customers".* FROM "customers" WHERE "customers"."id" = ? LIMIT 1
[["id", 111]] Completed 400 Bad Request in 5ms (ActiveRecord: 0.2ms)
ActionController::ParameterMissing (param is missing or the value is empty: order): app/controllers/order_controller.rb:107:in
order_params' app/controllers/order_controller.rb:44:in
createorders'
Rendered /Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_source.erb
(8.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.6ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
(1.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb
within rescues/layout (68.2ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb
(0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb
within layouts/inlined_string (0.4ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb
within layouts/javascript (60.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb
within layouts/javascript (0.3ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.5ms) Rendered
/Users/cecil/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb
(124.2ms)
Thank you stackoverflow for showing me support. I am new with ruby, and i understand i am making noob mistakes. So pointing out flaws are welcome!
I was ignoring your minor, non-fatal issues earlier while I was focused on locating the major issue, but I'll include them now that the major issue is apparent.
First, I'll discuss Rails naming conventions a little bit. You have two models, which are named Customer and Order. You've used the singular form of the noun for these, which is good. Each instance of a model is one thing, so it should be singular. Your controller for the Order model actions, however, should be named with the plural form, so it should be called OrdersController. This is because it controls the actions related to all of your orders. This leads us to your createorders action, which would make a little more sense if it were named createorder, since it only creates one Order. Actually, though, the convention is to name that action create. The action is in your OrdersController, so we already assume that it deals with an Order instance. (When you have Rails automatically generate REST-ful routes for a model's controller with the resources function, it assumes you have an action named create.) Lastly, in your create method, the new Order instance that will be referenced in your view should be called #order instead of #orders, since it contains only one Order.
Now things get a little more complicated. Your param is missing error means exactly that. The parameters for the new Order instance are missing. The request to the server that is producing that error is a GET request that has only one parameter, which you're providing in your URL with ?id=111. Your form's data is not being submitted to the server with that GET request. You should be doing a POST request to create a new Order. I'm going to avoid further exploration (and speculation without seeing your full code) regarding why things aren't working right now and I'll just suggest some key adjustments. It's turning in to a bit a puzzle to figure out how your app works without seeing all of the pieces.
In routes.rb, you should have this line:
resources :customers, :orders
I've made minimal changes to the view you provided, which I assume is called show.html.erb and is in your app/views/customers folder:
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="subject new">
<h2>Create Subject</h2>
<%= form_for #order do |f| %>
<table summary="subject form fields">
<tr>
<th>pakket</th>
<td><%= f.text_field(:pakket) %></td>
</tr>
<tr>
<th>verstuurt</th>
<td><%= f.text_field(:verstuurt) %></td>
</tr>
</table>
<%= f.hidden_field :customer_id %>
<div class="form-buttons">
<%= submit_tag("Create Subject") %>
</div>
<% end %>
</div>
Here is the necessary code from customers_controller.rb to support it:
def show
customer = Customer.find params[:id]
#order = customer.orders.new
end
Notice, in the view, the parameter for form_for is the instance that was created in the controller. Also, I've added a hidden field to submit the customer_id with the new Order data.
Finally, your create action in orders_controller.rb might look like this:
def create
#order = Order.new(order_params)
if #order.save
flash[:notice] = "Subject created successfully"
redirect_to(:action => 'index')
else
render 'customers/show'
end
end
And your order_params method should be changed to include the customer_id parameter:
def order_params
params.require(:order).permit(:pakket, :verstuurt, :customer_id)
end
Notice that on a failed save, the action renders customers/show, because this is the page that they were on where the save failed. This will allow Rails to re-populate the form (in the same context) with the data that was present during the failed submission.

multiparameter attributes error for date_select

I added just this one piece of coding to app and now it doesn't allow anyone to register. I receive the following error: 1 error(s) on assignment of multiparameter attributes. The title of the error page is "ActiveRecord::MultiparameterAssignmentErrors in UsersController#create". I am not sure how to fix as other posts were not helpful unfortunately. Anyone have some solutions?
new.html.erb:
<div class="field">
<%= f.label :birthday %>
<%= f.date_select :birthday, :start_year => 1995, :end_year => 1930 %>
</div>
users_controller:
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
development.log:
Started POST "/users" for 127.0.0.1 at 2013-03-22 10:27:31 -0400
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7KAgvcc6yvuhKQGNrJo8UpfsUyuNG16TuMsRj6qst48=", "user"=>{"email"=>"james#james.com", "password"=>"[FILTERED]", "username"=>"james", "zip_code"=>"84784", "gender"=>"women", "age"=>"23", "age_end"=>"39", "birthday(1i)"=>"1995", "birthday(2i)"=>"3", "birthday(3i)"=>"22", "role"=>"admin"}, "commit"=>"Create User"}
Completed 500 Internal Server Error in 100ms
ActiveRecord::MultiparameterAssignmentErrors (1 error(s) on assignment of multiparameter attributes):
app/controllers/users_controller.rb:18:in `new'
app/controllers/users_controller.rb:18:in `create'
The actual problem was the value in database was on VARCHAR, and instead it should be DATE. Now it works fine.
First make sure that the type of the birthday should be Date.
Here in parameters, the values for birthday is going like below.
"birthday(1i)"=>"1995", "birthday(2i)"=>"3", "birthday(3i)"=>"22"
But the type of the field id Date. So as i think, before updating the birthday field, we need to generate the appropriate date object and then need to update the object.
#user.birthday = Date.strptime("#{params['birthday(3i)']}/#{params['birthday(2i)']}/#{params['birthday(1i)']}", "%d/%m/%y")
Now save the object and hopefully it will not raise any error this time.
If still having error, pls let me know.

Rails 3.1: accepts_nested_attributes_for and has_one association - won't work?

I'm trying to use accepts_nested_attributes_for on a has_one association model, and getting absolutely nowhere :-(
I have two models, a user and a location. A user has one location:
class User < ActiveRecord::Base
# current location
has_one :location, :dependent => :destroy
accepts_nested_attributes_for :location
end
class Location < ActiveRecord::Base
belongs_to :user
end
I can save changes to the model by using User.find(1).location.current_location_text = "blah" from the console, so I know the associations are set up correctly.
I have two forms on the edit user page. One that updates the main user attributes (and works fine and not shown below) and then this one that allows the user to update an attribute of the location model, called "current_location_text":
<%= form_for(#user) do |f| %>
<%= fields_for(#user.location) do |location_fields| %>
<%= location_fields.label :current_location_text, 'Current Location' %>
<%= location_fields.text_field :current_location_text, :placeholder => 'Road, City or Postcode' %>
<% end %>
<%= f.submit "Update Current Location" %>
<% end %>
This doesn't work. I'm slightly confused as the params sent by the form look incorrect. When the form is submitted, this is in the log:
Started PUT "/users/1" for 127.0.0.1 at 2011-10-08 00:28:05 +0100
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"YdTAsXwEvRgXIqri+jfx3dLlYG2XWQTuYkgLDsO/OJw=", "location"=>{"current_location_text"=>"E14 8JS"}, "commit"=>"Update Current Location", "id"=>"1"}
User Load (10.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (5.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1 [["id", "1"]]
SQL (4.4ms) BEGIN
(2.5ms) COMMIT
Redirected to http://localhost:3000/users/1
Two things that I find bizarre about this:
There's the "COMMIT" message, but with no preceding update string, and no error. eg, if you tried to commit a protected attributed, you'd get the "you can't mass assign..." error message at that point.
The params look wrong to me. The "location" bit is nested as I'd expect, but I'd also expect this to be a nested within the "user" hash, something like this:
{"utf8"=>"✓", "authenticity_token"=>"YdTAsXwEvRgXIqri+jfx3dLlYG2XWQTuYkgLDsO/OJw=", "user"=>{"location"=>{"current_location_text"=>"E14 8JS"}, "commit"=>"Update Current Location", "id"=>"1"}}
I don't think I'm being completely stupid here. Am I missing something really obvious? I've tried adding extra hidden fields to my form, ie a user id, and then I get the user hash, but at the same level as the "location" hash, and not as a parent of it as I'd expect!
Also if it helps, here's my update within my UsersController:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
redirect_to current_user, :notice => 'User was successfully updated.'
else
render :action => "edit"
end
end
and here's what's in my routes.rb (although I don't think it's relevant):
resources :users do
resource :location
end
Any help appreciated. If I don't solve this, the laptop is going out the window....
Thanks.
<%= fields_for(#user.location) do |location_fields| %>
This is your problem. You need to actually "nest" the fields_for inside your form, like this:
<% f.fields_for(#user.location) do |location_fields| -%>
Try this instead
<%= f.fields_for :location do |location_fields| %>
Rather than giving it the object itself, tell rails what association you want to have it load for

Resources