I'm having a baffling problem. I have a LineItem model that accepts nested attributes for a Trackable and a Product. I am overriding the default trackable_attributes= and product_attributes= methods to allow me to find or initialize records. For example:
def trackable_attributes=(attributes)
_trackable = Project.find_or_initialize_by_id(attributes.delete("id"))
_trackable.attributes = attributes
self.trackable = _trackable
end
When I post to the LineItemController#create, even when there's only a logging statement in it, it runs all of the posted parameters as if I'm trying to build/create a new line item. I don't have any before_filters that would be doing this on the #create method.
def create
logger.info("LineItemsController#create")
end
Webserver logs:
Started POST "/line_items" for 127.0.0.1 at 2013-04-10 14:02:13 -0700
Processing by LineItemsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MY_SECRET_TOKEN", "line_item"=>{"trackable_type"=>"Project", "tax_rate"=>"0", "price"=>"0.00", "provided_on_formatted"=>"Apr 10", "trackable_attributes"=>{"company_attributes"=>{"id"=>"87", "name"=>"Handmade Design"}, "id"=>"45", "name"=>"MEdia Blitz"}, "product_attributes"=>{"id"=>"75"}, "name"=>"Design", "notes"=>"Yellow", "quantity"=>"0.00", "unit_price"=>"205.0"}, "commit"=>"+"}
Person Load (0.3ms) SELECT "people".* FROM "people" WHERE "people"."id" = 73 LIMIT 1
(0.1ms) begin transaction
(0.4ms) UPDATE "people" SET "last_request_at" = '2013-04-10 21:02:13.861629', "perishable_token" = 'kzsB5dnCOHfykO1XMMi9', "updated_at" = '2013-04-10 21:02:13.863622' WHERE "people"."id" = 73
[paperclip] Saving attachments.
(1.2ms) commit transaction
Account Load (0.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = 369 LIMIT 1
Person Load (0.3ms) SELECT "people".* FROM "people" WHERE "people"."account_id" = 369 ORDER BY id LIMIT 1
{"company_attributes"=>{"id"=>"87", "name"=>"Handmade Design"}, "id"=>"45", "name"=>"MEdia Blitz"}
Project Load (0.2ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = 45 LIMIT 1
Company Load (0.2ms) SELECT "companies".* FROM "companies" WHERE "companies"."id" = 87 LIMIT 1
trackable_attributes=(attributes)
trackable assigned
{"id"=>"75"}
Product Load (0.2ms) SELECT "products".* FROM "products" WHERE "products"."id" = 75 LIMIT 1
product_attributes=(attributes)
product assigned
LineItemsController#create
Notice that I have many logging statements scattered through my custom accepts_nested_attributes_for setters that are being called before the #create method even begins.
Is this normal? It seems to be causing problems with when I want to instantiate a new line_item the normal way in my LineItemsController#create method.
I'd really appreciate any help as I'm lost on where to start.
Related
So I have a model that has an enum value like so:
class Connection < ActiveRecord::Base
enum request_status: { pending: 0, accepted: 1, rejected: 2, removed: 3 }
end
But, I have a params value that I want to set and do a where query on - something like this:
#connections = current_user.all_connections.where(request_status: params[:request_status])
current_user.all_connections returns an AR object (aka...it is also a query method with a where call).
The issue I am facing is that right now, the above query returns an empty collection. The reason I believe is that per the API docs in Rails:
Where conditions on an enum attribute must use the ordinal value of an
enum.
Given that params[:request_status] will look like this:
Parameters: {"request_status"=>"accepted"}
How would I modify that where query to reflect this? I know one other option is just to modify the parameter to be the ordinal value, rather than the string, but I am curious how I might achieve this with the string value rather than the ordinal value?
Edit 1
Here are the server logs:
Started GET "/connections?request_status=accepted" for 127.0.0.1 at 2016-01-04 20:23:08 -0500
Processing by ConnectionsController#index as HTML
Parameters: {"request_status"=>"accepted"}
User Load (2.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
FamilyTree Load (1.7ms) SELECT "family_trees".* FROM "family_trees" WHERE "family_trees"."user_id" = $1 LIMIT 1 [["user_id", 3]]
Connection Load (2.0ms) SELECT "connections".* FROM "connections" WHERE "connections"."invited_user_id" = $1 ORDER BY "connections"."created_at" DESC [["invited_user_id", 3]]
Connection Load (1.8ms) SELECT "connections".* FROM "connections" WHERE "connections"."inviter_user_id" = $1 ORDER BY "connections"."created_at" DESC [["inviter_user_id", 3]]
Connection Load (2.2ms) SELECT "connections".* FROM "connections" WHERE (connections.invited_user_id = 3 OR connections.inviter_user_id = 3) AND "connections"."request_status" = 0 ORDER BY "connections"."created_at" DESC
Rendered connections/index.html.erb within layouts/connections (0.3ms)
Rendered connections/_header.html.erb (2.8ms)
Rendered shared/_navbar.html.erb (61.2ms)
Rendered shared/_footer.html.erb (3.2ms)
Rendered layouts/application.html.erb (1142.4ms)
Completed 200 OK in 1184ms (Views: 1155.5ms | ActiveRecord: 10.4ms)
Edit 2
This is the index action for that controller.
def index
params[:request_status] = "pending" if params[:request_status].nil?
#connections = current_user.all_connections.where(request_status: params[:request_status]).order(created_at: :desc).group_by { |c| c.created_at.to_date }
end
What's strange is that for every action that I click on that should send the correct request_status it still sends the SQL with request_status = 0.
I commented out the params[:request_status] = setter in the controller to see if that was doing it, but it wasn't it.
What could be causing this issue?
Here is another log for a different status:
Started GET "/connections?request_status=rejected" for 127.0.0.1 at 2016-01-04 21:30:29 -0500
Processing by ConnectionsController#index as HTML
Parameters: {"request_status"=>"rejected"}
User Load (2.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
FamilyTree Load (1.5ms) SELECT "family_trees".* FROM "family_trees" WHERE "family_trees"."user_id" = $1 LIMIT 1 [["user_id", 3]]
Connection Load (1.4ms) SELECT "connections".* FROM "connections" WHERE "connections"."invited_user_id" = $1 ORDER BY "connections"."created_at" DESC [["invited_user_id", 3]]
Connection Load (1.0ms) SELECT "connections".* FROM "connections" WHERE "connections"."inviter_user_id" = $1 ORDER BY "connections"."created_at" DESC [["inviter_user_id", 3]]
Connection Load (1.2ms) SELECT "connections".* FROM "connections" WHERE (connections.invited_user_id = 3 OR connections.inviter_user_id = 3) AND "connections"."request_status" = 0 ORDER BY "connections"."created_at" DESC
Rendered connections/index.html.erb within layouts/connections (0.2ms)
Rendered connections/_header.html.erb (2.5ms)
Rendered shared/_navbar.html.erb (60.3ms)
Rendered shared/_footer.html.erb (3.0ms)
Rendered layouts/application.html.erb (1103.8ms)
Completed 200 OK in 1130ms (Views: 1112.5ms | ActiveRecord: 7.3ms)
You can use Connection.request_statuses["pending"] to get 0.
So you can use string in your query like this:
#connections = current_user.all_connections.where(request_status: Connection.request_statuses[params[:request_status]])
I have a table subscription with a column status. In my subscriptions controller I have a method accept_player that is supposed to update the subscription.status to "confirmed!"
def accept_player
#subscription = Subscription.find(params[:subscription_id_accept_player])
#subscription.status = "confirmed!"
#subscription.save
authorize #subscription
redirect_to tournament_subscriptions_path(#subscription.tournament)
end
unfortunately every time I try to trigger that method, a rollback seem to take place:
Started POST "/accept_player/39" for ::1 at 2015-07-08 22:01:21 +0100
ActiveRecord::SchemaMigration Load (12.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
/Users/davidgeismar/code/davidgeismar/tennis-match/app/controllers/subscriptions_controller.rb:141: warning: duplicated key at line 155 ignored: "CardType"
Processing by SubscriptionsController#accept_player as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"aas8OPHBpvPwNbbmx/SVipsRM+eKo63nuVilMroxKcU9HRVonjSqEuH7aLY91gFi9PHMUsUqRqk7qhnv2m4L/A==", "subscription_id_accept_player"=>"39", "commit"=>"Confirmer ce Joueur", "subscription_id"=>"39"}
User Load (13.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
Subscription Load (11.6ms) SELECT "subscriptions".* FROM "subscriptions" WHERE "subscriptions"."id" = $1 LIMIT 1 [["id", 39]]
(5.7ms) BEGIN
Subscription Exists (0.8ms) SELECT 1 AS one FROM "subscriptions" WHERE ("subscriptions"."user_id" = 20 AND "subscriptions"."id" != 39 AND "subscriptions"."tournament_id" = 9) LIMIT 1
(12.6ms) ROLLBACK
Tournament Load (2.4ms) SELECT "tournaments".* FROM "tournaments" WHERE "tournaments"."id" = $1 LIMIT 1 [["id", 9]]
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 2]]
Redirected to http://localhost:3000/tournaments/9/subscriptions
Completed 302 Found in 246ms (ActiveRecord: 79.7ms)
Any ideas about what might be going wrong here ?
This code:
authorize #subscription
is probably causing the rollback. If you're in dev mode, just comment it out, reload!, and try to manually add a record and see if that's the cause.
I have a lot of cases in my app where a user has no more than one object (say, a "Description") within its association to another object (a "Group").
For example:
class User < ActiveRecord::Base
has_many :descriptions
has_many :groups
class Group < ActiveRecord::Base
has_many :users
has_many :descriptions
class Description < ActiveRecord::Base
belongs_to :user
belongs_to :group
If I wanted to render all the users in certain group and include their relevant descriptions, I could do something this:
#users model
def description_for(group_id)
descriptions.find_by_group_id(group_id)
end
#view
#group.users.each do |user|
user.name
user.description_for(#group.id).content
But this generates a huge number of Description queries. I've tried using joins:
#controller
#group = Group.find(params[:id], :joins => [{:users => :descriptions}], :conditions => ["descriptions.group_id = ?", params[:id]])
But since I'm still calling user.description_for(#group.id) it doesn't help with the page loading.
UPDATE: Sample generated SQL
Rendered users/_title.html.haml (1.6ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 7 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 7 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 7 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 51 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 51 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 51 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.8ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.1ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 5 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 5 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 37 LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 52 LIMIT 1
CACHE (0.0ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = 28 LIMIT 1
Description Load (0.2ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 52 AND "descriptions"."group_id" = 28 LIMIT 1
CACHE (0.0ms) SELECT "descriptions".* FROM "descriptions" WHERE "descriptions"."target_id" = 52 AND "descriptions"."group_id" = 28 LIMIT 1
Rendered users/_title.html.haml (1.7ms)
Right, I think that actually you don't need the joins clause in rails 3. If you use include and where, Arel will do the hard work for you.
I've tested this (albeit using a different set of models (and attributes) than yours) using models with the same underlying arrangement of associations, and I think this should work:
in models/user.rb:
scope :with_group_and descriptions, lambda { |group_id| includes(:groups, :descriptions).where(:groups => { :id => group_id }, :descriptions => { :group_id => group_id }) }
Then in your controller you call:
#users = User.with_group_and_descriptions(params[:id])
Finally in the view you can then do:
#users.each do |user|
user.name
user.descriptions.each do |desc|
desc.content
# or
#users.each do |user|
user.name
user.descriptions[0].content
If I've gotten my thinking right then this should only make 2 db calls. One to get a list of user_ids and the second to get the user, group and description data, and even though you're calling a user object's descriptions method, which would ordinarily have all the descriptions in (not just the ones for a particular group), because you've already populated the association rails won't go off an grab all the associations again when you call user.descriptions, instead it'll just list the ones you've pulled from the DB using the descriptions.group_id where clause. Calling user.descriptions(true) however will force a reload of the descriptions leading to it returning an array of all the description associations for a user.
Take a look at include--it specifies an association that should be eager-loaded.
Railscasts #181: Include vs Joins (or the ASCIIcast version)
Ruby on Rails Guides - see section 4.1.2.7
I have the following:
class User < ActiveRecord::Base
before_update :guest_upgrade
def guest_upgrade
# If the user changed their email that means they were a guest, and are no longer.
# Likely triggered from the Registrations#Update controller
if self.email_changed?
self.guest = false
end
end
This is causing rollbacks, here is the log with the above in play:
Started POST "/users" for 127.0.0.1 at 2011-07-18 14:54:00 -0700
Processing by RegistrationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x+u1DSDanU2QXK/q0=", "user"=>{"fname"=>"xxxxx", "lname"=>"xxxx", "email"=>"xxxxxxx#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"1"}, "commit"=>"Create my account", "fb_access_token"=>"", "fb_uuid"=>""}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
SQL (0.1ms) BEGIN
User Load (0.5ms) SELECT "users"."id" FROM "users" WHERE ("users"."email" = 'xxxxxxx#gmail.com') AND ("users".id <> 5) LIMIT 1
SQL (0.2ms) ROLLBACK
Authentication Load (0.5ms) SELECT "authentications".* FROM "authentications" WHERE "authentications"."provider" = 'facebook' AND ("authentications".user_id = 5) LIMIT 1
Rendered layouts/_header.html.erb (3.9ms)
CACHE (0.0ms) SELECT "authentications".* FROM "authentications" WHERE "authentications"."provider" = 'facebook' AND ("authentications".user_id = 5) LIMIT 1
Rendered registrations/edit.html.erb within layouts/application (107.0ms)
Completed 200 OK in 484ms (Views: 111.7ms | ActiveRecord: 6.0ms)
Yet if I comment out the guest_upgrade it works fine:
Started POST "/users" for 127.0.0.1 at 2011-07-18 14:55:23 -0700
Processing by RegistrationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xxxxx+u1DSDanU2QXK/q0=", "user"=>{"fname"=>"XXXX", "lname"=>"XXXX", "email"=>"xxxx#gmail.com"}, "commit"=>"Save Changes"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
SQL (0.1ms) BEGIN
User Load (0.4ms) SELECT "users"."id" FROM "users" WHERE ("users"."email" = 'xxxx#gmail.com') AND ("users".id <> 5) LIMIT 1
AREL (0.7ms) UPDATE "users" SET "fname" = 'XXXX', "lname" = 'XXXX', "email" = 'xxxx#gmail.com', "updated_at" = '2011-07-18 21:55:23.817142' WHERE "users"."id" = 5
[paperclip] Saving attachments.
SQL (37.9ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 780ms
Am I using the dirty objects incorrectly?
All I want to do is, when User is updated, if the user changes there email, change the user.guest field to false.
Suggestions? Thanks
I think I've had this problem before. I believe what's happening is it's returning false; try adding an explicit return like so:
if self.email_changed?
self.guest = false
return true
end
Check out the section marked Canceling Callbacks at ruby on rails.org api. It reads:
Canceling callbacks
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.
I know I'm late but I hope this helps!
I have an ajax request that is causing problems in my Rails 3.0.9 app. I can see the problem in the logs, but I don't have any idea what is triggering it between the ajax call and the render. Here's the log, and the event I don't want with ** beside it:
Started DELETE "/notifications/13" for 127.0.0.1 at 2011-06-21 22:08:39 -0500
Processing by NotificationsController#destroy as JS
Parameters: {"id"=>"13"}
SQL (0.4ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
SQL (0.3ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Slug Load (0.4ms) SELECT "slugs".* FROM "slugs" WHERE ("slugs".sluggable_id = 1 AND "slugs".sluggable_type = 'User') ORDER BY id DESC LIMIT 1
****AREL (0.3ms) UPDATE "users" SET "remember_token" = NULL, "remember_created_at" = NULL, "updated_at" = '2011-06-22 03:08:40.084049', "preferences" = '---
:email_notifications: ''true''
' WHERE "users"."id" = 1
Notification Load (0.2ms) SELECT "notifications".* FROM "notifications" WHERE "notifications"."id" = 13 LIMIT 1
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
AREL (0.3ms) UPDATE "users" SET "notifications_count" = COALESCE("notifications_count", 0) - 1 WHERE "users"."id" = 1
AREL (0.1ms) DELETE FROM "notifications" WHERE "notifications"."id" = 13
Completed 200 OK in 1334ms
I'd like to somehow step by step debug this request, sort of like the way you can step through a function in javascript using firebug.
Is there a way to debug like this so I can see how that specific AREL command is getting called??
Have you looked at ruby on rails guides - debugging?? you can debug just like in gdb
This railscast is also quite useful.