Rails is allowing double post request to lock database? - ruby-on-rails

I'm using Valums Ajax Uploader to create a nice user interface for uploading photos in my rails app. One problem, it sometimes submits Post requests too close together, and then they cause a database locking exception which makes all the uploads fail for a while.
Here's an example of the log:
Started POST "/photos?authenticity_token=WPJo8nnJ3KSoG9O%2B%2Flz%2BPbvdtX8cmbEaVB8TidnLx5Y%3D&qqfile=IMG_0417.JPG" for 127.0.0.1 at 2012-03-06 22:39:25 -0600
Processing by PhotosController#create as HTML
Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x007f9e5529f518 #original_filename="IMG_0417.JPG", #content_type="application/octet-stream", #headers=nil, #tempfile=#<File:/var/folders/mf/06zfbjcn63j6p2rqvt6tc77c0000gn/T/raw-upload.20120306-53350-13pew0o>>, "authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0417.JPG"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Started POST "/photos?authenticity_token=WPJo8nnJ3KSoG9O%2B%2Flz%2BPbvdtX8cmbEaVB8TidnLx5Y%3D&qqfile=IMG_0418.JPG" for 127.0.0.1 at 2012-03-06 22:39:30 -0600
Processing by PhotosController#create as HTML
Parameters: {"file"=>#<ActionDispatch::Http::UploadedFile:0x007fcfddd8d268 #original_filename="IMG_0418.JPG", #content_type="application/octet-stream", #headers=nil, #tempfile=#<File:/var/folders/mf/06zfbjcn63j6p2rqvt6tc77c0000gn/T/raw-upload.20120306-53383-1plhm8r>>, "authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0418.JPG"}
"authenticity_token"=>"WPJo8nnJ3KSoG9O+/lz+PbvdtX8cmbEaVB8TidnLx5Y=", "qqfile"=>"IMG_0418.JPG"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.1ms) begin transaction
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
SQL (0.6ms) INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["city", nil], ["comments_updated_at", nil], ["context_id", nil], ["country", nil], ["created_at", Tue, 06 Mar 2012 22:39:37 CST -06:00], ["custom_title", nil], ["description", nil], ["featured", false], ["flagged", nil], ["focus_id", nil], ["full_downloads", 0], ["height", 2304], ["image", "admin_tester_630cm1715.JPG"], ["lat", nil], ["lng", nil], ["place", nil], ["presentation_downloads", 0], ["state", nil], ["status", "batch"], ["updated_at", Tue, 06 Mar 2012 22:39:37 CST -06:00], ["user_id", 1], ["width", 3072]]
SQL (0.2ms) UPDATE "users" SET "photos_count" = COALESCE("photos_count", 0) + 1 WHERE "users"."id" = 1
(0.1ms) begin transaction
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
SQL (5064.0ms) INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["city", nil], ["comments_updated_at", nil], ["context_id", nil], ["country", nil], ["created_at", Tue, 06 Mar 2012 22:39:43 CST -06:00], ["custom_title", nil], ["description", nil], ["featured", false], ["flagged", nil], ["focus_id", nil], ["full_downloads", 0], ["height", 2304], ["image", "admin_tester_630cm171b.JPG"], ["lat", nil], ["lng", nil], ["place", nil], ["presentation_downloads", 0], ["state", nil], ["status", "batch"], ["updated_at", Tue, 06 Mar 2012 22:39:43 CST -06:00], ["user_id", 1], ["width", 3072]]
SQLite3::BusyException: database is locked: INSERT INTO "photos" ("city", "comments_updated_at", "context_id", "country", "created_at", "custom_title", "description", "featured", "flagged", "focus_id", "full_downloads", "height", "image", "lat", "lng", "place", "presentation_downloads", "state", "status", "updated_at", "user_id", "width") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(0.3ms) rollback transaction
SQLite3::BusyException: cannot rollback transaction - SQL statements in progress: rollback transaction
Completed 500 Internal Server Error in 17749ms
ActiveRecord::StatementInvalid (SQLite3::BusyException: cannot rollback transaction - SQL statements in progress: rollback transaction):
app/controllers/photos_controller.rb:29:in `create'
app/uploaders/flash_session_cookie_middleware.rb:16:in `call'
Obviously this isn't good, if this happens with just one user uploading a few images it isn't up to production standards. So, how do you fix this? What is the right way to handle uploading and processing a file like this so that concurrency isn't a big problem?

You might want to migrate from SQLite if you're having multiple processes accessing the same database. While this is supported by SQLite, it does require a lock on the entire database to avoid corrupting data during commits. This is explained in rough terms in the SQLite FAQ.
While SQLite is great for small-scale databases and development work, it is probably not the best idea for a production grade application that sees a lot of write activity.
The good news is that converting from SQLite to MySQL or Postgres is usually very simple.
You could be hitting some kind of deadlock condition due to the way SQLite handles locking. It's also odd that your uploads would be taking such an extended period of time to process.

Related

accept_nested_attributes_for creates one extra nil record on Rails

I am using Rails as a backend and React as my front-end. On the React side, I am using fetch to do POST request to my model named schedule. I am also adding a child attributes for worker model.
Here are some code snippets that I have. I am using has_many :through relationship in rails.
My Rails models and controller:
//schedule.rb
has_many :workers, through: :rosters, dependent: :destroy
has_many :rosters, inverse_of: :schedule
//worker.rb
has_many :schedules, through: :rosters
has_many :rosters, inverse_of: :worker
//roster.rb
belongs_to :schedule
belongs_to :worker
//schedules_controller.rb
def create
#schedule = Schedule.new(schedule_params)
#workers = #schedule.rosters.build.build_worker
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
...
def schedule_params
params.permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])
end
On React side:
//inside Client.js
function postSchedule(date, cb) {
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1,
workers_attributes: [{name: "Iggy Test", phone: "123-456-7890"}, {name: "Iggy Test 2", phone: "987-654-3210"}]
})
}).then((response) => response.json())
.then(cb);
};
//inside main app:
postSchedule(){
Client.postSchedule(this.state.date, (schedule) => {
this.setState({schedules: this.state.schedules.concat([schedule])})
})
};
The problem that I have is, when I submit a new schedule, I expect to see a new schedule with two workers: "Iggy Test" and "Iggy Test 2". However, when I looked inside Rails, it is creating 3 workers: "Iggy Test", "Iggy Test 2", and nil.
Here is what is happening when I submit the request:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-24 09:55:16 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}, {"name"=>"Iggy Test 2", "phone"=>"987-654-3210"}], "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "use
r_id"=>1}}
Unpermitted parameter: schedule
(0.1ms) begin transaction
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["date", 20
17-05-27 02:00:00 UTC], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC], ["user_id", 1]
]
SQL (0.2ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test"], ["phone", "123-456-7890"], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 64], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.1ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test 2"], ["phone", "987-654-3210"], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.1ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 65], ["c
reated_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2017-05-24 16:55:16 UTC
], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["sc
hedule_id", 57], ["worker_id", 66], ["created_at", 2017-05-24 16:55:16 UTC], ["updated_at", 2017-05-24 16:55:16 UTC]]
SQL (0.7ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 60]]
SQL (0.1ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 57],
["updated_at", 2017-05-24 16:55:16 UTC], ["id", 61]]
(2.6ms) commit transaction
Completed 200 OK in 68ms (Views: 0.8ms | ActiveRecord: 5.6ms)
The log created a schedule, then a worker (Iggy Test), then a roster (for that schedule and Iggy Test), then another worker (Iggy Test 2), then another roster (for Iggy Test 2 and that schedule) - instead of stopping, it created another worker (nil) and a roster for that nil worker.
Why is it behaving such? How can I fix it to create only the specified workers?
As a side note - if you noticed, the log says unpermitted parameter: schedule. That message disappears when I add require(:schedule) inside my schedule_params, but it would instead create only one nil worker.
accepts_nested_attributes_for is not creating an extra record. You are.
def create
#schedule = Schedule.new(schedule_params)
# This adds a worker with no attributes
#workers = #schedule.rosters.build.build_worker
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
"Unpermitted parameter: schedule" is just a warning that there was a param is in the params hash that was not whitelisted by .permit. It is logged since it could be a malicious attempt to fish for mass assignment vulnerabilities.
.require takes a single key from the params hash and raises an error if it not present and is not what you want when you have a flat params hash.
Instead you should look into why the params sent by react include both the unwrapped params and I don't get why you are sending both the unwrapped params and a "schedule"=>{"date"=>"2017-05-27T02:00:00.000Z", "user_id"=>1} hash. I don't really know React but I'm guessing it has something to do with this.state.schedules.concat([schedule])

Rails 5 accepts_nested_attributes_for unpermitted parameter error? (React front end)

I have looked at previous SO solutions on accepts_nested_attributes here and here, but I am still getting the error. I am using React as front end and Rails back end. I am trying to create a request to be sent to schedules, and from there to populate to workers.
I am using Rails 5.0.2. I have a schedule, worker, roster models.
//Schedule
has_many :workers, through: :rosters, dependent: :destroy
has_many :rosters
accepts_nested_attributes_for :workers #implement accept_nested_attributes here
//Roster
belongs_to :schedule
belongs_to :worker
//Worker
has_many :schedules, through: :rosters
has_many :rosters
And here is my Schedule controller:
def create
#schedule = Schedule.new(schedule_params)
if #schedule.save
render json: #schedule
else
render json: #schedule, status: :unprocessable_entity
end
end
...
private
def schedule_params
params.permit(:date, :user_id, :workers_attributes => [:worker_id, :name, :phone])
end
Here is the error that I got:
app/controllers/schedules_controller.rb:13:in `create'
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 10:30:38 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>{"name"=>"Iggy Test", "phone"=>"1
23-456-7890"}, "schedule"=>{"date"=>"2017-05-25T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
Completed 500 Internal Server Error in 15ms (ActiveRecord: 0.0ms)
TypeError (no implicit conversion of Symbol into Integer):
app/controllers/schedules_controller.rb:13:in `create'
Why is my request shows Unpermitted parameter schedule? If I remove workers_attributes and only have params.permit(:date, :user_id), it works. I can't figure out why the error points to schedule. How can I make successful POST nested_attributes request to rails?
I am using fetch to do POST request from react side:
...
return fetch(`api/schedules`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
date: date,
user_id: 1,
workers_attributes: {name: "Iggy Test", phone: "123-456-7890"}
})
EDIT:
After following answer from #gabrielhilal, I added require(): params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone]), and edited the fetch POST on React's end to have array of objects instead of plain objects: workers_attributes: [{name: "Iggy Test", phone: "123-456-7890"}]. It does not complain anymore, and it does register new schedule. However, new workers are all nil:
#Worker.last shows:
#<Worker id: 32, name: nil, phone: nil, created_at: "2017-05-23 19:36:09", updated_at: "2017-05-23 19:36:09">
Sorry, don't mean to create nested question, but does anyone know why it is nil?
EDIT 2:
I got it to work, sort of.
If I have
def create
#schedule = Schedule.new(schedule_params)
#workers = #schedule.rosters.build.build_worker
...
and
//schedule_params
params.permit(:date, :user_id, :workers_attributes => [:id, :name, :pho
ne])
I was able to have "Iggy Test" to display, but it immediately creates another nil worker.
Log:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:42:38 -0700
Processing by SchedulesController#create as */*
Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
Unpermitted parameter: schedule
(0.1ms) begin transaction
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (1.1ms) INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC], ["user_id", 1]
]
SQL (0.2ms) INSERT INTO "workers" ("name", "phone", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Iggy
Test"], ["phone", "123-456-7890"], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.2ms) INSERT INTO "rosters" ("worker_id", "created_at", "updated_at") VALUES (?, ?, ?) [["worker_id", 56], ["c
reated_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.1ms) INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2017-05-24 03:42:38 UTC
], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.6ms) INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["sc
hedule_id", 52], ["worker_id", 57], ["created_at", 2017-05-24 03:42:38 UTC], ["updated_at", 2017-05-24 03:42:38 UTC]]
SQL (0.4ms) UPDATE "rosters" SET "schedule_id" = ?, "updated_at" = ? WHERE "rosters"."id" = ? [["schedule_id", 52],
["updated_at", 2017-05-24 03:42:38 UTC], ["id", 52]]
(5.6ms) commit transaction
Completed 200 OK in 417ms (Views: 6.9ms | ActiveRecord: 14.7ms)
If I modified params to have require(:schedule)
params.require(:schedule).permit(:date, :user_id, :workers_attributes => [:id, :name, :phone])
It creates a nil worker only.
Log:
Started POST "/api/schedules" for 127.0.0.1 at 2017-05-23 20:45:03 -0700
Processing by SchedulesController#create as */*
  Parameters: {"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1, "workers_attributes"=>[{"name"=>"Iggy Test", "phone"=>"
123-456-7890"}], "schedule"=>{"date"=>"2017-05-26T02:00:00.000Z", "user_id"=>1}}
   (0.1ms)  begin transaction
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.4ms)  INSERT INTO "schedules" ("date", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)  [["date", 20
17-05-26 02:00:00 UTC], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC], ["user_id", 1]
]
  SQL (0.2ms)  INSERT INTO "workers" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", 2017-05-24 03:45:03 UTC
], ["updated_at", 2017-05-24 03:45:03 UTC]]
  SQL (0.3ms)  INSERT INTO "rosters" ("schedule_id", "worker_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sc
hedule_id", 53], ["worker_id", 58], ["created_at", 2017-05-24 03:45:03 UTC], ["updated_at", 2017-05-24 03:45:03 UTC]]
   (2.4ms)  commit transaction
Completed 200 OK in 81ms (Views: 1.3ms | ActiveRecord: 8.3ms)
Your post:
{
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1,
"workers_attributes"=>{
"name"=>"Iggy Test",
"phone"=>"123-456-7890"
},
"schedule"=> {
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1
}
}
You have two issues:
schedule is not permitted (that's why you see the message in the logs), but it will be just ignored anyway (won't raise any error).
the workers_attributes should be a collection of workers and not a simple hash, so that's why you are having the error.
You should get something like the following in the post request:
{
"date"=>"2017-05-25T02:00:00.000Z",
"user_id"=>1,
"workers_attributes"=>{
"0" => {
"name"=>"Iggy Test",
"phone"=>"123-456-7890"
}
}
}

Rails two step signup with devise - Errors

I am trying to set-up a two step signup process using Devise in Rails and followed this tutorial by Claudio Marai.
When I enter the e-mail address in the form (first step), I get an error telling me there was a routing error and that it couldn't find RegistrationsController
Started POST "/users" for 127.0.0.1 at 2012-05-03 22:50:59 -0400
ActionController::RoutingError (uninitialized constant RegistrationsController):
activesupport (3.2.1) lib/active_support/inflector/methods.rb:229:in `block in constantize'
activesupport (3.2.1) lib/active_support/inflector/methods.rb:228:in `each'
activesupport (3.2.1) lib/active_support/inflector/methods.rb:228:in `constantize'
.
.
.
I figured this was due to the presence of :registrations => "registrations" in my routes.rb file as described in the first step of the tutorial. I then tried two alternatives which both resulted in the same error. First, I removed the :registrations => "registrations" from the routes.rb file. When that didn't work, I re-inserted the line and added a registrations_controller.rb to the controllers directory which looked like this:
class RegistrationsController < Devise::RegistrationsController
end
I figured the two options would have the same effect - but - I tried them anyway.
The error I got was the following:
Started POST "/users" for 127.0.0.1 at 2012-05-03 22:47:29 -0400
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"?", "authenticity_token"=>"ttPBRPRLVzPBHcDDKRJbimv0Yp/egdK5qBkIvBTL4Ig=", "user"=>{"email"=>"test#email.com"}, "x"=>"0", "y"=>"0"}
(0.6ms) begin transaction
User Exists (1.5ms) SELECT 1 FROM "users" WHERE "users"."email" = 'test#email.com' LIMIT 1
CACHE (0.0ms) SELECT 1 FROM "users" WHERE "users"."email" = 'test#email.com' LIMIT 1
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '8tA1jakpAXNK4Piz7J6R' LIMIT 1
SQL (14.0ms) INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "confirmed_at", "created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "fb_id", "fb_token", "first_name", "last_name", "last_sign_in_at", "last_sign_in_ip", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "state", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["confirmation_sent_at", Thu, 03 May 2012 22:47:30 EDT -04:00], ["confirmation_token", "8tA1jakpAXNK4Piz7J6R"], ["confirmed_at", nil], ["created_at", Thu, 03 May 2012 22:47:30 EDT -04:00], ["current_sign_in_at", nil], ["current_sign_in_ip", nil], ["email", "test#email.com"], ["encrypted_password", nil], ["fb_id", nil], ["fb_token", nil], ["first_name", nil], ["last_name", nil], ["last_sign_in_at", nil], ["last_sign_in_ip", nil], ["remember_created_at", nil], ["reset_password_sent_at", nil], ["reset_password_token", nil], ["sign_in_count", 0], ["state", nil], ["updated_at", Thu, 03 May 2012 22:47:30 EDT -04:00]]
SQLite3::ConstraintException: constraint failed: INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "confirmed_at", "created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "fb_id", "fb_token", "first_name", "last_name", "last_sign_in_at", "last_sign_in_ip", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "state", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
(0.3ms) rollback transaction
Completed 500 Internal Server Error in 441ms
ActiveRecord::StatementInvalid (SQLite3::ConstraintException: constraint failed: INSERT INTO "users" ("confirmation_sent_at", "confirmation_token", "confirmed_at", "created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "fb_id", "fb_token", "first_name", "last_name", "last_sign_in_at", "last_sign_in_ip", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "state", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)):
sqlite3 (1.3.5) lib/sqlite3/statement.rb:108:in `step'
sqlite3 (1.3.5) lib/sqlite3/statement.rb:108:in `block in each'
sqlite3 (1.3.5) lib/sqlite3/statement.rb:107:in `loop'
sqlite3 (1.3.5) lib/sqlite3/statement.rb:107:in `each'
.
.
.
The above error has me really confused!
With the same form, when I add the password and password_confirmation fields, then things proceed smoothly - the user account is created and a confirmation email is sent to the user with the confirmation link.
I would appreciate any help regarding this - thanks! I am using Ruby 1.9.3-p125 and Rails 3.2.1
The issue isn't due to Rails validation, it's due to a violation of a database constraint.
More than likely, if your users table migration was generated by Devise, then the schema includes this:
"encrypted_password" varchar(128) DEFAULT '' NOT NULL
The SQL that's causing the ConstraintException includes this (elided for readability):
SQL (14.0ms) INSERT INTO "users" (..., "encrypted_password", ...) VALUES (..., ?, ...) [..., ["encrypted_password", nil], ...]
So, something is telling your database adapter to set encrypted_password = nil.
You should be able to circumvent it either be running a migration that removes the NOT NULL constraint on the encrypted_password, or do as you've done, pass in an encrypted_password, but just make sure it's empty in the first step, but present in the second step.

In Rails, why would saving a new record return nil, and nothing gets saved?

I initialize an AdUnit object au with
au = AdUnit.new( cp )
where cp is equal to:
{:name=>"second56", :description=>nil, :target_window=>"BLANK", :explicitly_targeted=>false, :ad_unit_sizes_attributes=>[{:height=>90, :width=>728, :is_aspect_ratio=>false, :environment_type=>"BROWSER"}], :dfp_id=>"22319511", :parent_id_dfp=>"22261791"}
and the resulting object au is
#<AdUnit id: nil, dfp_id: "22319511", parent_id_dfp: "22261791", parent_id_bulk: nil, name: "second56", description: nil, target_window: "BLANK", explicitly_targeted: false, created_at: nil, updated_at: nil>
At this point, au.valid? and au.new_record? both return true.
If I do au.save (or au.save! for that matter) the result is nil and nothing is saved to the database. but if I do
aud = au.dup
aud.save
the result is true and the record is saved.
I can save my object with the duplicate workaround, but this looks really weird to me. can anybody give any ideas as to why is this happening? Below the SQL fragments from the 2 save statements from Rails console.
Thanks in advance all Rails gurus.
Returning nil and not saving:
SQL (1.0ms) INSERT INTO "ad_units" ("created_at", "description", "dfp_id", "explicitly_targeted", "name", "parent_id_bulk", "parent_id_dfp", "target_window", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) [["created_at", Wed, 04 Jan 2012 17:28:37 UTC +00:00], ["description", nil], ["dfp_id", "22400631"], ["explicitly_targeted", false], ["name", "zapiFirstLevel366"], ["parent_id_bulk", nil], ["parent_id_dfp", "1166751"], ["target_window", "BLANK"], ["updated_at", Wed, 04 Jan 2012 17:28:37 UTC +00:00]]
=> nil
Returning true and saving:
SQL (0.9ms) INSERT INTO "ad_units" ("created_at", "description", "dfp_id", "explicitly_targeted", "name", "parent_id_bulk", "parent_id_dfp", "target_window", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) [["created_at", Wed, 04 Jan 2012 17:29:58 UTC +00:00], ["description", nil], ["dfp_id", "22400631"], ["explicitly_targeted", false], ["name", "zapiFirstLevel366"], ["parent_id_bulk", nil], ["parent_id_dfp", "1166751"], ["target_window", "BLANK"], ["updated_at", Wed, 04 Jan 2012 17:29:58 UTC +00:00]]
=> true
OK, this was caused by the usage of accepts_nested_attributes_for when AdUnit has a has_and_belongs_to_many relationship with AdUnitSize. So I got to learn that these 2 do not work together nicely.
The only thing is, it might be good to have a warning somewhere, instead of having to find out about it from .save returning nil on a valid? = true object instead of true or false.
Using save! raises an exception if the record is invalid. It doesn't return anything.
If you need a return value use only save.
Basically if save! didn't raise, the record is saved successfuly. If you don't see it, then you're probably loading it wrong.

rails 3 accepts_nested_attributes_for not working when save

I have declared the accepts_nested_attributes_for and everything works fine but only when I save the model into the database, the nested model is not saved along the master model, anyone know why?
In my log/development.log file:
Started POST "/users/1/business_infos" for 127.0.0.1 at 2011-10-22 23:08:59 -0500
Processing by BusinessInfosController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Vw9GWH4cnr8z+PPged0mal/CVsbdBM1NcDehRb7zl7Q=", "business_info"=>{"business_name"=>"microsoft", "locations_attributes"=>{"0"=>{"address"=>"New York, NY"}, "1"=>{"address"=>""}, "2"=>{"address"=>""}}, "business_hours"=>"5am-7pm, Mon - Fri", "business_logo"=>#<ActionDispatch::Http::UploadedFile:0xa219684 #original_filename="rails.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"business_info[business_logo]\"; filename=\"rails.png\"\r\nContent-Type: image/png\r\n", #tempfile=#<File:/tmp/RackMultipart20111022-28086-fbv7x6>>, "business_phone"=>"6666666666", "business_web_addr"=>"www.microsoft.com"}, "commit"=>"Create", "user_id"=>"1"}
[1m[36mUser Load (0.3ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", "1"]]
[1m[35mSQL (4.9ms)[0m INSERT INTO "business_infos" ("business_addr", "business_hours", "business_logo", "business_name", "business_phone", "business_web_addr", "confirmed", "created_at", "multi_location", "qr_code", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["business_addr", nil], ["business_hours", "5am-7pm, Mon - Fri"], ["business_logo", "/assets/business_logo/microsoft.png"], ["business_name", "microsoft"], ["business_phone", "6666666666"], ["business_web_addr", "www.microsoft.com"], ["confirmed", nil], ["created_at", Sun, 23 Oct 2011 04:08:59 UTC +00:00], ["multi_location", nil], ["qr_code", nil], ["updated_at", Sun, 23 Oct 2011 04:08:59 UTC +00:00], ["user_id", 1]]
[1m[36mBusinessInfo Load (0.2ms)[0m [1mSELECT "business_infos".* FROM "business_infos" WHERE "business_infos"."user_id" = 1 LIMIT 1[0m
[1m[35m (1.0ms)[0m UPDATE "business_infos" SET "qr_code" = '/assets/qr_code/microsoft.png', "updated_at" = '2011-10-23 04:09:00.314348' WHERE "business_infos"."id" = 8
Redirected to http://localhost:3000/users/1
Completed 302 Found in 613ms
if you see Parameters in the log, there contains a location_attributes(location model), which is the nested attributes for business_info model, but if you see the INSERT INTO "business_infos" query, there are no insertion to the location table!
I have posted a more detailed question at this link Rails mode accepts_nested_attributes_for working properly Any clue?

Resources