I am trying to assign parent as superadmin. when i run the command parent.toggle!(superadmin) it doesnt assign the parent as superadmin.
I am not able to locate the error
irb(main):004:0> parent.toggle!(:superadmin)
(0.2ms) begin transaction
Parent Update (0.6ms) UPDATE "parents" SET "updated_at" = ?, "superadmin" = ? WHERE "parents"."id" = ? [["updated_at", "2018-06-20 17:50:31.273816"], ["superadmin", 1], ["id", 1]]
Parent Update (0.2ms) UPDATE "parents" SET "updated_at" = ?, "superadmin" = ? WHERE "parents"."id" = ? [["updated_at", "2018-06-20 17:50:31.280343"], ["superadmin", 0], ["id", 1]]
(1.8ms) commit transaction
=> true
it seems that the transaction is beign done, remember that toggle doesn't assign true, it changes the false to true a viceversa, depending on the current value that it has.
on the example you are sending, it's changed to true at first but then again to false. you are doing it right talking about code. but maybe there is a callback that changes again the value to false before saving it. Check on your model if there are callbacks or if you have some rules for this.
Related
I have a rails application with 3 models (Job, Order, Fulfillment). The relationship between the models is:
Order has one Job
Fulfillment has many Jobs
The Jobs table has the following Schema:
create_table "jobs", force: :cascade do |t|
t.string "type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "order_id"
t.integer "fulfillment_id"
end
Lets say I have an Order o and a Fulfillment f
o.job = Job.create!(:order_id => o.id, :fulfillment_id => f.id)
This creates a job associated to o and f.
But if I try to execute the same statement again, I get an ActiveRecord::RecordNotSaved error but there exists a new Job entry in the table.
The same error is seen if I try to create the Job via the following method:
o.create_job!(:fulfillment_id => f.id)
Stack Trace:
(0.1ms) begin transaction
Order Load (0.2ms) SELECT "orders".* FROM "orders" WHERE "orders"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]]
Fulfillment Load (0.2ms) SELECT "fulfillments".* FROM "fulfillments" WHERE "fulfillments"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Job Create (0.4ms) INSERT INTO "jobs" ("created_at", "updated_at", "order_id", "fulfillment_id") VALUES (?, ?, ?, ?) [["created_at", "2018-07-23 06:27:33.519957"], ["updated_at", "2018-07-23 06:27:33.519957"], ["order_id", 4], ["fulfillment_id", 1]]
(0.8ms) commit transaction
(0.1ms) begin transaction
(0.7ms) rollback transaction
Traceback (most recent call last):
1: from (irb):82
ActiveRecord::RecordNotSaved (Failed to remove the existing associated job. The record failed to save after its foreign key was set to nil.)
Why is this possible? If the association is being breached, and the transaction has been rolled-back, the table entry should have been deleted?
When exactly is Rails checking for failing association? How do I rescue from this error without having to manually delete the incorrect entry in the table?
It's happen due to your has_one associations.
will fail because it is trying to delete the original order, but that one can't
be deleted because there is a validation on job_id.
This is because prior to deleting, the foreign key of the target association is set to nil and a save operation is performed on the target.
Please refer https://github.com/rails/rails/issues/17325
Here I'm testing the changes in current_user.messages.count after the current user sends a valid message. Here's my code:
spec
scenario 'adds to their messages', js: true do
expect { find('#message_content').send_keys(:enter) }.to \
change(current_user.messages, :count).by(1)
end
test.log
# ...
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel_1
(0.6ms) SELECT COUNT(*) FROM "messages" WHERE "messages"."user_id" = $1 [["user_id", 1]]
ConversationChannel#send_message({"content"=>"foobar\n", "conversation_id"=>"1"})
(0.3ms) BEGIN
(0.9ms) SELECT COUNT(*) FROM "messages" WHERE "messages"."user_id" = $1 [["user_id", 1]]
Conversation Load (1.6ms) SELECT "conversations".* FROM "conversations" WHERE "conversations"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.7ms) SELECT "users"."id" FROM "users" INNER JOIN "user_conversations" ON "users"."id" = "user_conversations"."user_id" WHERE "user_conversations"."conversation_id" = $1 [["conversation_id", 1]]
SQL (1.0ms) INSERT INTO "messages" ("content", "user_id", "conversation_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "foobar\n"], ["user_id", 1], ["conversation_id", 1], ["created_at", "2018-01-29 11:27:13.095277"], ["updated_at", "2018-01-29 11:27:13.095277"]]
Finished "/cable/" [WebSocket] for 127.0.0.1 at 2018-01-29 19:27:13 +0800
ConversationChannel stopped streaming from conversation_channel_1
(0.2ms) BEGIN
(58.8ms) COMMIT
(16.7ms) ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" DISABLE TRIGGER ALL;ALTER TABLE "conversations" DISABLE TRIGGER ALL;ALTER TABLE "messages" DISABLE TRIGGER ALL;ALTER TABLE "user_conversations" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
Rendered messages/_message.html.erb (0.6ms)
[ActionCable] Broadcasting to conversation_channel_1: {:message=>"<p>User 1: foobar\n</p>\n"}
# ...
The spec fails expected #count to have changed by 1, but was changed by 0 even though in the log shows INSERT INTO actually happen.
This doesn't work because you're not waiting long enough for the message addition to actually occur. send_keys returns as soon as the browser has been sent the key event, but knows nothing at all about any request/action triggered by that key press in the browser. This is why direct DB access tests are generally a bad idea in feature/system tests (which should generally just test user visible changes/interactions) and make more sense as request or controller.
That being said you could fix this by just sleeping after sending the key, but a better solution is to use one of the Capybara provided matchers (have waiting/retrying behavior) to synchronize the test.
scenario 'adds to their messages', js: true do
expect do
find('#message_content').send_keys(:enter) }
expect(page).to have_css(...) # check for whatever visible change on the page indicates the action triggered by send_keys has completed
end.to change { current_user.reload.messages.count }.by(1)
end
Note: This test is also very simple for a feature test. It's okay to have multiple expectations in a feature test since it's really meant to test a whole user interaction with a specific feature of your app. You might want to look at combining this test with other tests of the same part of your app.
Try to write :
change{current_user.messages, :count}.by(1)
with {}
I have one particular user in my rails app for which I can't log in anymore, the password is always invalid, even though I changed it manually. Here's what I do in rails console :
> me = User.find(10)
> me.password = '123456789'
> me.save
(0.3ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" = 'myemail#gmail.com' AND "users"."id" != 10) LIMIT 1
SQL (0.7ms) UPDATE "users" SET "encrypted_password" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["encrypted_password", "$2a$10$mrhWiOT3pu6YldtYRD/bC.wuqPthyfJhiqdGkYv14xCafVQNTodWG"], ["updated_at", "2016-08-08 10:43:34.715229"], ["id", 10]]
(31.3ms) COMMIT
=> true
> me.valid_password?('123456789')
=> nil
This is only with this particular user id 10. I do the exact same thing with any other user it works. What could be wrong ?
EDIT : I tried also with password confirmation but that's not the issue. As I said, the exact manipulation works fine with any user except this one of ID 10
EDIT 2 : I found the solution in this thread : Rails/Devise: valid_password? method returns nil
I think probably you need to set password_confirmation as well, Try below code.
> me = User.find(10)
> me.password = '123456789'
> me.password_confirmation = '123456789'
> me.save
I have an object that looks like this:
It is used to allows users with resumes to 'apply to' (job)listings.
# == Schema Information
#
# Table name: jobapps
#
# id :integer not null, primary key
# denied :boolean
# listing_id :integer
# resume_id :integer
# created_at :datetime
# updated_at :datetime
#
class Jobapp < ActiveRecord::Base
belongs_to :listing
belongs_to :resume
validates_uniqueness_of :listing_id, scope: :resume_id
before_save :default_values
. . .
private
def default_values
if self.denied.nil?
self.denied = false
end
end
end
Whenever I create a new Jobapp object, the job always fails.
If I change the default_values method on the Jobapps model to:
def default_values
if denied.nil?
self.denied = false
pp self
end
end
The object is created and saved.
Console Output:
When I attempt to have a Resume object apply_to a Listing object, which should create a Jobapp object:
Started POST "/listings/1/apply?resume=8" for 127.0.0.1 at 2014-07-31 18:43:33 -0500
Processing by ListingsController#apply as HTML
Parameters: {"authenticity_token"=>"htbHjaZnkqRMfgSUAQA5zOXB3ax/MAaHRUx8jRWr/lw=", "resume"=>"8", "id"=>"1"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Listing Load (0.2ms) SELECT "listings".* FROM "listings" WHERE "listings"."id" = $1 LIMIT 1 [["id", "1"]]
(0.2ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
Resume Load (0.2ms) SELECT "resumes".* FROM "resumes" WHERE "resumes"."id" = $1 LIMIT 1 [["id", "8"]]
(0.2ms) BEGIN
Jobapp Exists (0.2ms) SELECT 1 AS one FROM "jobapps" WHERE ("jobapps"."listing_id" = 1 AND "jobapps"."resume_id" = 8) LIMIT 1
(0.1ms) ROLLBACK
Redirected to http://0.0.0.0:3000/listings/1
Completed 302 Found in 102ms (ActiveRecord: 1.5ms)
When I have the pp self line in the default_values method:
Started POST "/listings/1/apply?resume=8" for 127.0.0.1 at 2014-07-31 18:41:36 -0500
Processing by ListingsController#apply as HTML
Parameters: {"authenticity_token"=>"htbHjaZnkqRMfgSUAQA5zOXB3ax/MAaHRUx8jRWr/lw=", "resume"=>"8", "id"=>"1"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Listing Load (0.2ms) SELECT "listings".* FROM "listings" WHERE "listings"."id" = $1 LIMIT 1 [["id", "1"]]
(2.3ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
Resume Load (0.3ms) SELECT "resumes".* FROM "resumes" WHERE "resumes"."id" = $1 LIMIT 1 [["id", "8"]]
(0.1ms) BEGIN
Jobapp Exists (0.2ms) SELECT 1 AS one FROM "jobapps" WHERE ("jobapps"."listing_id" = 1 AND "jobapps"."resume_id" = 8) LIMIT 1
"here it is"
#<Jobapp id: nil, denied: false, listing_id: 1, resume_id: 8, created_at: nil, updated_at: nil>
SQL (0.3ms) INSERT INTO "jobapps" ("created_at", "denied", "listing_id", "resume_id", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Thu, 31 Jul 2014 23:41:36 UTC +00:00], ["denied", false], ["listing_id", 1], ["resume_id", 8], ["updated_at", Thu, 31 Jul 2014 23:41:36 UTC +00:00]]
(0.5ms) COMMIT
Redirected to http://0.0.0.0:3000/listings/1
Completed 302 Found in 120ms (ActiveRecord: 4.9ms)
Some referenced methods:
Here is the apply method from the controller:
def apply
set_resume
if #resume.apply_to(#listing)
redirect_to #listing
else
redirect_to #listing, alert: 'Unable to apply for job'
end
end
Here is the Resume.apply_to method:
def apply_to(listing)
jobapp = Jobapp.new(resume: self, listing: listing)
jobapp.save
end
Notes:
It smells like I'm doing something weird with the conditional apply method (which is annoying) but I don't think that's the reason for the failure (it fails if I take out the odd conditional and simplify the Resume.apply_to method to simply create the object rather than using new then save.
Pretty Print ruby doc
From what I can tell, this is because self.denied = false returns false, and so your callback is returning false, which will cancel all future callbacks and associated action:
If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.
http://api.rubyonrails.org/v4.1.1/classes/ActiveRecord/Callbacks.html
Just make sure your default_values method returns true.
From the ActiveRecord Callbacks documentation:
If a before_* callback returns false, all the later callbacks and the associated action are cancelled.
And in your callback you have:
if self.denied.nil?
self.denied = false
end
So if you keep in mind that all blocks (including if blocks, methods, begin/end blocks, etc.) return the last value in the block... then you're affectively returning false from your callback. That is:
self.denied = false sets self.denied to false an then returns false
The if block surrounding this returns the last value in the block, or false
The method returns the last value in the method (block), or false
Therefore, your callback cancels the save operation.
Furthermore, when you introduced the pp self statement, then that will effectively output self and then return self, which is not false (obviously).
So to fix the non pp self version, I would recommend just returning true at the end since you're most likely not looking to abort the save after evaluating the contents of your callback method. Here it is, slightly simplifed using the idiomatic ||= operator.
def default_values
self.denied ||= false
true
end
The use of ||= above is the same as: self.denied || self.denied = false.
I'm trying to create many copies of a message to users:
users.each do |user|
new_message = message.clone
new_message.to = user
new_message.save!
end
However, this doesn't work after the 1st user. Here's part of the error message:
SQL (0.7ms) INSERT INTO "messages" ("content", "to_id") VALUES (?, ?) [["content", "abc"], ["to_id", 1]]
(2.5ms) commit transaction
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
(0.0ms) begin transaction
SQL (0.5ms) INSERT INTO "messages" ("content", "id", "to_id") VALUES (?, ?, ?) [["content", "abc"], ["id", 6], ["to_id", 2]]
SQLite3::ConstraintException: PRIMARY KEY must be unique: INSERT INTO "messages" ("content", "id", "to_id") VALUES (?, ?, ?)
(0.0ms) rollback transaction
Completed 500 Internal Server Error in 130.1ms
ActiveRecord::StatementInvalid (SQLite3::ConstraintException: PRIMARY KEY must be unique: INSERT INTO "messages" ("content", "id", "to_id") VALUES (?, ?, ?)):
As you can see, the problem is that the 2nd time the loop runs, message.clone must contain the id of the previous new_message.
What is the proper way to clone message records for many users? I can, of course, manually copy each attribute (I have a lot more than just content and to_id) into a fresh new Message object. But I'd like to know if there's a better way.
You can use dup, with which the id, created_at and updated_at are set to nil. This will ensure that Primary Key exception is not thrown, however if there are other unique validations, they will fail. You'd have to handle them separately.
users.each do |user|
new_message = message.dup
new_message.to = user
new_message.save!
end