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.
Related
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".
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.
I wonder if anyone can help me to understand about the difference between build and create in Has Many Through (HMT) relationship?
From my understanding after reading through stackoverflow and google, create is essentially build + save. However, it seems like create does more than just build + save. It also somehow save into the join table of the HMT relationship as shown below.
I created 3 models: user, wiki, and collaborator.
class User < ActiveRecord::Base
has_many :wikis, through: :collaborators
has_many :collaborators
end
class Wiki < ActiveRecord::Base
has_many :users, through: :collaborators
has_many :collaborators
end
class Collaborator < ActiveRecord::Base
belongs_to :user
belongs_to :wiki
end
Then I tested the build and create behavior in rails console:
$rails c
Loading development environment (Rails 4.0.10)
> user = User.first #create instance user
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, name: "Jayzz55">
> (user.wikis.build(title:"hello",body:"world")).save #build and save wiki
SQL INSERT INTO "wikis" ("body", "created_at", "title", "updated_at") VALUES(?,?,?,?) [["body","world"], ["ccreated_at, Sat, 08 Nov 2014 01:39:36 UTC +00:00], ["title","hello"], ["updated_at",Sat, 08 Nov 2014 01:39:36 UTC +00:00]]
=> true
>wiki1 = Wiki.first #create instance wiki called wiki1
=> #<Wiki id:1, title:"hello",body:"world">
>user.wikis
=> #<Wiki id:1, title:"hello",body:"world">
>user.wikis.count
=> 0
>wiki1.users
=> []
>Collaborator.all
=> []
> user.wikis.create(title:"second title",body:"another one")
begin transaction
SQL INSERT INTO "wikis" ("body", "created_at", "title", "updated_at") VALUES (?, ?, ?, ?)[0m [["body", "another one"], ["created_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["title", "second title"], ["updated_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00]]
SQL INSERT INTO "collaborators" ("created_at", "updated_at", "user_id", "wiki_id") VALUES (?, ?, ?, ?) [["created_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["updated_at", Sat, 08 Nov 2014 01:59:39 UTC +00:00], ["user_id", 1], ["wiki_id", 2]]
=> #<Wiki id:2, title:"second title",body:"another one>
>user.wikis
=> [#<Wiki id: 1, title:"hello",body:"world">, #<Wiki id:2, title:"second title",body:"another one>]
>user.wikis.count
=> 1
>wiki2.users
=>#<User id: 1, name: "Jayzz55">
>Collaborator.all
Collaborator Load SELECT "collaborators".* FROM "collaborators"
=> #<Collaborator id:`, user_id:1, wiki_id: 2>
Case wiki1 : build and then save it
The data is not saved into the join table. calling user.wikis does return the object wiki, but running user.wikis.count return 0. Furthermore, running wiki1.users doesn't return the object user. Checking the join table Collaborator returns empty array.
Case wiki2 : create
The data is saved into the join table. calling user.wikis does return the object wiki. Running user.wikis.count return 1. Furthermore, running wiki1.users does return the object user. Checking the join table Collaborator, it does show the relationship clearly mapped.
Seems like Create is not simply just build + new. I'm curious about this behavior and hopefully someone can share their knowledge on this.
I believe that if you had in your first case instead written:
user.wikis.build(title:"hello",body:"world")
user.save
... you would find that ActiveRecord does the "full" save that create also does. The way you've written it, you're asking ActiveRecord to save the newly created Wiki instance, but not the association. So it doesn't create the record in the join table that's required.
Build + Save is equivalent to Create in any relationship
Newbie here, trying to add some rules to a ruby on rails form, specifically I don't want to allow the creation of an item if this has not a name
class Idea < ActiveRecord::Base
mount_uploader :picture, PictureUploader
belongs_to :project
validates :name, presence: true, allow_nil: false
end
Works smoothly if I create a new item from my app, but not happens the same if I create one item from rails console. How can I avoid the creation of an item without name, no matter if this has been created in the app or in the rails console?
The problem is you have to set allow_blank: false instead of allow_nil: false.
In Ruby an empty string is not nil.
"".nil?
#=> false
"".blank?
#=> true
Update your model like this
class Idea < ActiveRecord::Base
mount_uploader :picture, PictureUploader
belongs_to :project
validates :name, presence: true, allow_blank: false
end
If you want know the differences between nil and blank,see this SO post.
Refer these Guides for allow_blank
Try this from console:-
Idea.create(:name => "Something")
Rails console output:-
1.9.3-p385 :005 > c = CabinNumber.create(:name => "Something")
(0.2ms) begin transaction
SQL (1.1ms) INSERT INTO "cabin_numbers" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 25 May 2014 00:02:04 IST +05:30], ["name", "Something"], ["status", false], ["updated_at", Sun, 25 May 2014 00:02:04 IST +05:30]]
(139.6ms) commit transaction
=> #<CabinNumber id: 11, name: "Something", status: false, created_at: "2014-05-24 18:32:04", updated_at: "2014-05-24 18:32:04">
OR
idea = Idea.new(:name => "hello")
idea.save
Rails console output:-
1.9.3-p385 :007 > c = CabinNumber.new(:name => "hello")
=> #<CabinNumber id: nil, name: "hello", status: false, created_at: nil, updated_at: nil>
1.9.3-p385 :008 > c.save
(0.1ms) begin transaction
SQL (1.0ms) INSERT INTO "cabin_numbers" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 25 May 2014 00:02:57 IST +05:30], ["name", "hello"], ["status", false], ["updated_at", Sun, 25 May 2014 00:02:57 IST +05:30]]
(155.0ms) commit transaction
=> true
Cannot create if name field is not provided
1.9.3-p385 :003 > c = CabinNumber.create()
(0.2ms) begin transaction
(0.1ms) rollback transaction
=> #<CabinNumber id: nil, name: nil, status: false, created_at: nil, updated_at: nil>
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.