Attribute Not Updating - ruby-on-rails

Model
class Pm < ActiveRecord::Base
attr_accessor :name
end
Console
me = Pm.new
#=> <Pm id: nil, name: nil, created_at: nil, updated_at: nil>
me.name = "Josh"
#=> "Josh"
me.save
#=>(0.4ms) BEGIN
#=> true
#=> SQL (0.8ms) INSERT INTO "pms" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["created_at", Sat, 01 Jun 2013 19:02:27 UTC +00:00], ["name", nil], ["updated_at", Sat, 01 Jun 2013 19:02:27 UTC +00:00]]
#=>(1.3ms) COMMIT
me
#=> <Pm id: 4, name: nil, created_at: "2013-06-01 19:02:27", updated_at: "2013-06-01 19:02:27">
I have a model with a name attribute and an attr_accessor defined. The record saves but it doesn't update the name attribute. Am I missing something simple here?

If your Pmp model ("Pimp"? "Pump"? "Pimple"?) has a DB field called "name", there's no reason to use attr_accessor :name. With attr_accessor :name, ActiveRecord's dynamically generated attribute methods will never be invoked, and yes, it means the attribute won't be saved to the database.

Related

Return virtual Postgres column after create

I have a Rails 7 model that uses Postgres' virtual column feature:
create_table :time_entries do |t|
# ...
t.virtual :duration, type: :interval, as: %(("to" - "from")::interval), stored: true, null: false
# ...
end
The problem is, that after I create a record via Rails create(...) these virtual column is nil:
[16] pry(main)> TimeEntry.create(from: Time.zone.now, to: 1.day.from_now)
TRANSACTION (0.3ms) BEGIN
TimeEntry Create (0.5ms) INSERT INTO "time_entries" ("from", "to", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"
[["from", "2022-11-18 06:45:11.419000"], ["to", "2022-11-19 06:45:11.420000"], ["created_at", "2022-11-18 06:45:11.420862"], ["updated_at", "2022-11-18 06:45:11.420862"]]
TRANSACTION (0.9ms) COMMIT
=> #<TimeEntry:0x0000ffff86f1ae10
id: 13,
from: Fri, 18 Nov 2022 06:45:11.419000000 UTC +00:00,
to: Sat, 19 Nov 2022 06:45:11.420000000 UTC +00:00,
duration: nil,
created_at: Fri, 18 Nov 2022 06:45:11.420862000 UTC +00:00,
updated_at: Fri, 18 Nov 2022 06:45:11.420862000 UTC +00:00>
When you reload the model, duration is set.
I found out, that this is due to Rails only returning the id column using RETURNING "id" at the end of the INSERT INTO statement. When you execute the query in Postgres directly you can return the generated duration column directly after the insert:
app_development=# INSERT INTO "time_entries" ("from", "to", "created_at", "updated_at") VALUES ( '2022-11-18 06:34:46.889000', '2022-11-18 06:34:56.889000', '2022-11-18 06:34:46.889000', '2022-11-18 06:34:46.889000') RETURNING "duration", "id";
duration | id
----------+----
00:00:10 | 11
(1 row)
Is it possible to customize the RETURNING "id" part of the SQL query in my model, so that the instance of TimeEntry already have the duration set after I create it?
EDIT:
I found the code segment inside the Postgres Adapter and tried to monkey patch it like this:
require "active_record/connection_adapters/postgresql/database_statements"
module PostgresReturningPatch
def sql_for_insert(...)
sql, *args = super
if sql.include?(TimeEntry.table_name) && sql.ends_with?(%(RETURNING "id"))
returning_virtual_columns = TimeEntry::columns.select(&:virtual?).map do |column|
quote_column_name(column.name)
end.join(", ")
sql += ", #{returning_virtual_columns}"
end
binding.pry
[sql, *args]
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements.module_eval do
prepend PostgresReturningPatch
end
Unfortunately, it's still nil when Rails returns the instance of my model, despite that the SQL ends now with RETURNING "id", "date", "duration".

Rails simple model attributes not saved to database

I am developing a small Rails 3 app that reads data from the Steam API. What I am seeing is that the model attributes for any ActiveRecord model I create are not saved to the database nor are they output if I debug them.
Here my sample model
class NonPlayableApp < ActiveRecord::Base
attr_accessor :name, :steam_id
attr_accessible :name, :steam_id
end
With the migration file being:
class CreateNonPlayableApps < ActiveRecord::Migration
def change
create_table :non_playable_apps do |t|
t.string :name
t.string :steam_id
t.timestamps
end
end
end
Here are few tests with the Rails console, I get the same results when I try them in a controller and inspect or yaml the model:
irb(main):001:0> temp = NonPlayableApp.new( steam_id: 33333, name: "Testing" )
=> #<NonPlayableApp id: nil, name: nil, steam_id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> temp.steam_id
=> 33333
irb(main):003:0> temp.name
=> "Testing"
irb(main):004:0> temp.save
(0.1ms) begin transaction
SQL (4.0ms) INSERT INTO "non_playable_apps" ("created_at", "name", "steam_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 26 Feb 2016 19:40:37 UTC +00:00], ["name", nil], ["steam_id", nil], ["updated_at", Fri, 26 Feb 2016 19:40:37 UTC +00:00]]
(8.8ms) commit transaction
=> true
irb(main):005:0> temp.steam_id
=> 33333
irb(main):006:0> temp
=> #<NonPlayableApp id: 64, name: nil, steam_id: nil, created_at: "2016-02-26 19:40:37", updated_at: "2016-02-26 19:40:37">
irb(main):007:0> temp2 = NonPlayableApp.first
NonPlayableApp Load (1.6ms) SELECT "non_playable_apps".* FROM "non_playable_apps" LIMIT 1
=> #<NonPlayableApp id: 64, name: nil, steam_id: nil, created_at: "2016-02-26 19:40:37", updated_at: "2016-02-26 19:40:37">
irb(main):008:0> temp2.steam_id
=> nil
irb(main):009:0> temp2.name
=> nil
What am I missing?
attr_accessor :name, :steam_id overrides the setter and getter methods that Rails automatically generates for that attributes.
Just delete the attr_accessor :name, :steam_id line from your model.

Rails unable to save json in database

I want to save Json data in my Rails PostgreSQL database.
In my migration file
class IbmSubscription < ActiveRecord::Migration
def up
create_table :ibm_subscriptions do |t|
t.json 'ibm_response'
t.references :user, index: true
t.timestamps
end
end
def down
drop_table :ibm_subscriptions
end
end
I am unable to save JSON data in ibm_response
I tried this in rails console
2.1.5 :004 > a = JSON.parse(#uri.to_s)
=> {"type"=>"SUBSCRIPTION_ORDER", "marketplace"=>{"base_url"=>"https://acme.appdirect.com", "partner"=>"ACME"}, "flag"=>"STATELESS", "creator"=>{"email"=>"test-email+creator#appdirect.com", "first_name"=>"DummyCreatorFirst", "language"=>"fr", "last_name"=>"DummyCreatorLast", "open_id"=>"https://www.appdirect.com/openid/id/ec5d8eda-5cec-444d-9e30-125b6e4b67e2", "uuid"=>"ec5d8eda-5cec-444d-9e30-125b6e4b67e2"}, "payload"=>{"company"=>{"country"=>"CA", "email"=>"company-email#example.com", "name"=>"Example Company Name", "phone_number"=>"415-555-1212", "uuid"=>"d15bb36e-5fb5-11e0-8c3c-00262d2cda03", "website"=>"http://www.example.com"}, "configuration"=>{"entry"=>{"key"=>"domain", "value"=>"mydomain"}}, "order"=>{"edition_code"=>"BASIC", "pricing_duration"=>"MONTHLY", "item"=>[{"quantity"=>"10", "unit"=>"USER"}, {"quantity"=>"15", "unit"=>"MEGABYTE"}]}}, "return_url"=>"https://www.appdirect.com/finishprocure?token=dummyOrder", "#xmlns:atom"=>"http://www.w3.org/2005/Atom"}
2.1.5 :005 > a = IbmSubscription.create(ibm_response: #uri)
WARNING: Can't mass-assign protected attributes for IbmSubscription: ibm_response
(0.2ms) BEGIN
SQL (5.7ms) INSERT INTO "ibm_subscriptions" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", Fri, 02 Oct 2015 17:30:13 UTC +00:00], ["updated_at", Fri, 02 Oct 2015 17:30:13 UTC +00:00]]
(93.9ms) COMMIT
=> #<IbmSubscription id: 1, ibm_response: nil, user_id: nil, created_at: "2015-10-02 17:30:13", updated_at: "2015-10-02 17:30:13">
Its creating ibm_response: nil.
Please help me. Thanks
Can't mass-assign protected attributes for IbmSubscription
This line implies that you need to add :ibm_response to attr_accessible in your IbmSubscription model.

Adding JOIN for associated tables [duplicate]

This question already has an answer here:
Adding a JOIN between two tables
(1 answer)
Closed 9 years ago.
My Organization class looks something like this:
has_many Students
My Student class looks like this:
has_many Klasses
belongs_to Organization
My Klass class looks like this:
some field named : price
scope :top_expensive_classes, joins(:students).order('price DESC')
belongs_to Student
And my query looks like this:
#results = Klass.top_expensive_classes.where(organization_id: params[:id]).limit(RESULT_SET_COUNT)
Notice that it starts with Klass, so that's the problem because I am searching in the where class for organization_id but that is not in the Klass, it is in Student class , so somehow I should introduce a join somewhere to fix this but couldn't figure it out.
I think the real issue is your associations are likely incorrect.
A student has many classes
A class has many students
but what you have is
A student has many classes
A class belongs to a single student
This doesn't really make sense (at least in any situation I've ever seen a class and student interact). You should be creating a many-to-many relationship instead of a one-to-many relationship between Klass and Student.
class Student < ActiveRecord::Base
has_many :klasses, through: :student_klasses
has_many :student_klasses
end
class Klass < ActiveRecord::Base
has_many :students, through: :student_klasses
has_many :student_klasses
end
class StudentKlass < ActiveRecord::Base
belongs_to :student
belongs_to :klass
end
Once you have these correct associations in place, you need to call .joins on the :students association from the Klass class. You can do without the scope.
Klass.joins(:students).where("students.organization_id = ?", params[:id]).order('price DESC').limit(RESULT_SET_COUNT)
Read the guide on ActiveRecord Querying.
Here is the proof (using the exact model definitions above) that the ordering of the associations does not matter.
irb(main):001:0> s = Student.create(name: "Deefour")
SQL (3.6ms) INSERT INTO "students" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:33:32 UTC +00:00], ["name", "Deefour"], ["updated_at", Fri, 08 Mar 2013 01:33:32 UTC +00:00]]
=> #<Student id: 1, name: "Deefour", created_at: "2013-03-08 01:33:32", updated_at: "2013-03-08 01:33:32">
irb(main):002:0> kk = []
=> []
irb(main):003:0> kk << Klass.create(title: "Klass 1")
SQL (0.3ms) INSERT INTO "klasses" ("created_at", "title", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:06 UTC +00:00], ["title", "Klass 1"], ["updated_at", Fri, 08 Mar 2013 01:34:06 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">]
irb(main):004:0> kk << Klass.create(title: "Klass 2")
SQL (0.3ms) INSERT INTO "klasses" ("created_at", "title", "updated_at") VALUES (?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:14 UTC +00:00], ["title", "Klass 2"], ["updated_at", Fri, 08 Mar 2013 01:34:14 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">, #<Klass id: 2, title: "Klass 2", created_at: "2013-03-08 01:34:14", updated_at: "2013-03-08 01:34:14">]
irb(main):005:0> s.klasses = kk
Klass Load (0.1ms) SELECT "klasses".* FROM "klasses" INNER JOIN "student_klasses" ON "klasses"."id" = "student_klasses"."klass_id" WHERE "student_klasses"."student_id" = ? [["student_id", 1]]
SQL (0.4ms) INSERT INTO "student_klasses" ("created_at", "klass_id", "student_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00], ["klass_id", 1], ["student_id", 1], ["updated_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00]]
SQL (0.1ms) INSERT INTO "student_klasses" ("created_at", "klass_id", "student_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00], ["klass_id", 2], ["student_id", 1], ["updated_at", Fri, 08 Mar 2013 01:34:29 UTC +00:00]]
=> [#<Klass id: 1, title: "Klass 1", created_at: "2013-03-08 01:34:06", updated_at: "2013-03-08 01:34:06">, #<Klass id: 2, title: "Klass 2", created_at: "2013-03-08 01:34:14", updated_at: "2013-03-08 01:34:14">]
irb(main):006:0> Student.first.klasses.map(&:id)
Student Load (0.2ms) SELECT "students".* FROM "students" ORDER BY "students"."id" ASC LIMIT 1
Klass Load (0.1ms) SELECT "klasses".* FROM "klasses" INNER JOIN "student_klasses" ON "klasses"."id" = "student_klasses"."klass_id" WHERE "student_klasses"."student_id" = ? [["student_id", 1]]
=> [1, 2]

rails 3 create sets values to bill

So after a merge, my RoR 3 project no longer does 'creates' correctly. Default attributes get set correctly, but not the ones I pass in:
1.9.3-p125 :020 > f=Ifilter.create(:name => "test2", :regex => "()" )
SQL (101.5ms) INSERT INTO "ifilters" ("created_at", "name", "regex", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sat, 10 Mar 2012 03:36:24 UTC +00:00], ["name", nil], ["regex", nil], ["updated_at", Sat, 10 Mar 2012 03:36:24 UTC +00:00]]
=> #<Ifilter id: 2, name: nil, regex: nil, created_at: "2012-03-10 03:36:24", updated_at: "2012-03-10 03:36:24">
However, save still works:
1.9.3-p125 :021 > f=Ifilter.new
=> #<Ifilter id: nil, name: nil, regex: nil, created_at: nil, updated_at: nil>
1.9.3-p125 :022 > f.name = "test"
=> "test"
1.9.3-p125 :023 > f.regex = "()"
=> "()"
1.9.3-p125 :024 > f.save
SQL (4.8ms) INSERT INTO "ifilters" ("created_at", "name", "regex", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sat, 10 Mar 2012 04:13:10 UTC +00:00], ["name", "test"], ["regex", "()"], ["updated_at", Sat, 10 Mar 2012 04:13:10 UTC +00:00]]
=> true
What's going on?
Thanks!
Looks like you may have attr_accessible on your model. http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible
If you are using it, attributes that aren't explicitly listed won't get set via #new, #create, and #update_attributes (and a few more).
This usually happens when you have attribute whitelisting enabled. Make sure you define the attributes that are settable via mass-assignment in your model via the attr_accessible macro:
class Ifilter
attr_accessible :name, :regex
...
end

Resources