Am I missing something here?
Discourse model:
class Discourse < ActiveRecord::Base
#<Discourse id:, user_id: , sub_discourse_id: , title: , body: , deleted: , delete_date: , created_at:, updated_at: >
has_many :discourse_replies
has_many :replies, through: :discourse_replies
end
DiscourseReply model:
class DiscourseReply < ActiveRecord::Base
belongs_to :discourse
belongs_to :reply, class_name: 'Discourse'
end
console:
Loading development environment (Rails 4.0.2)
2.0.0p247 :001 > fd = Discourse.create(title: 'first', body: 'first')
=> #<Discourse id: 5, user_id: nil, sub_discourse_id: nil, title: "first", body: "first", deleted: nil, delete_date: nil, created_at: "2014-04-04 23:32:13", updated_at: "2014-04-04 23:32:13">
2.0.0p247 :002 > fd.discourse_replies
=> #<ActiveRecord::Associations::CollectionProxy []>
2.0.0p247 :004 > fd.create_discourse_reply
NoMethodError: undefined method 'create_discourse_reply' for #<Discourse:0x00000003396450>
2.0.0p247 :004 > fd.discourse_replies.build(title: "reply to first", body: "reply to first")
ActiveRecord::UnknownAttributeError: unknown attribute: title
In a nutshell, why is create_discourse_reply an undefined method?
You've defined has_many association for discourse_replies so to create a associated object you need to do
fd.discourse_replies.create
fd.create_discourse_reply would have been created the object if you'd have associated it with has_one or belongs_to association.
Related
ruby '2.7.3'
rails (6.1.4.1)
Looks strange:
When I query some (some specific) rows in DB using activerecord and try to assign it to a variable, it raises "nil can't be coerced into Integer"
But when I don't try to assign it to a variable, it works:
Recipient.find(45638)
=> #<Recipient id: 45638, company_id: 7, callout_id: 18, phone: "***", created_at: "2022-02-14 02:14:04.816032000 +0000", updated_at: "2022-02-15 06:50:37.828979000 +0000", payload: {"first_name"=>"", "last_name"=>"", "lead_id"=>"388014"}, started_at: nil, finished_at: 1644907333994, call_duration: 95, call_result: nil, report_data: {"Recording"=>"...", "UF_CRM_1601886091616"=>"76"}, job_status: "longCallWithResult", job_id: "2105242339", aasm_state: "finished", attempts: 1, tag: "...", tag_payload: {}, code: "37cca71006817c4f9e2e172d4e0afe80", schedule_at: "2022-02-11 09:07:47.000000000 +0000", synced_to_external_crm: false>
2.7.3 :035 > recipient = Recipient.find(45638)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
It happens only with specific rows in DB. Not only with model object, but with ActivRecord::Relation objects also:
Works:
recipients = Recipient.where(callout_id: 18).where('schedule_at IS NULL OR schedule_at <= ?', DateTime.current).limit(1).offset(5)
=> #<ActiveRecord::Relation [#<Recipient id: 45640, company_id: 7, callout_id: 18, phone: "***", created_at: "2022-02-14 04:59:10.175701000 +0000", updated_at: "2022-02-15 06:50:38.224724000 +0000", payload: {"firs...
Doesn't work:
2.7.3 :045 > recipients = Recipient.where(callout_id: 18).where('schedule_at IS NULL OR schedule_at <= ?', DateTime.current).limit(1).offset(6)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
Same issue happens with different models:
Model 'Callout':
2.7.3 :001 > callout = Callout.find 18
=> #<Callout id: 18, company_id: 7, name: "***", token: [FILTERED], created_at: "2021-12-19 13:50:51.383907000 +0000", updated_at: "2022-02-08 09:19:20.153542000 +0000", auto_queue: true>
2.7.3 :002 > callout = Callout.find 17
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
2.7.3 :003 > Callout.find 17
=> #<Callout id: 17, company_id: 1, name: "***", token: [FILTERED], created_at: "2021-11-27 11:07:30.927895000 +0000", updated_at: "2022-02-14 07:59:24.154910000 +0000", auto_queue: false>
2.7.3 :004 > Callout.find 18
=> #<Callout id: 18, company_id: 7, name: "***", token: [FILTERED], created_at: "2021-12-19 13:50:51.383907000 +0000", updated_at: "2022-02-08 09:19:20.153542000 +0000", auto_queue: true>
Model 'Company':
2.7.3 :005 > Company.find 7
=> #<Company id: 7, name: "***", created_at: "2021-12-19 13:39:12.045709000 +0000", updated_at: "2021-12-19 13:39:12.045709000 +0000", balance: 0, api_token: [FILTERED]>
2.7.3 :006 > c = Company.find 7
=> #<Company id: 7, name: "***", created_at: "2021-12-19 13:39:12.045709000 +0000", updated_at: "2021-12-19 13:39:12.045709000 +0000", balance: 0, api_token: [FILTERED]>
2.7.3 :008 > Company.find 1
=> #<Company id: 1, name: "***", created_at: "2021-10-22 12:23:19.831733000 +0000", updated_at: "2021-12-01 20:15:04.464389000 +0000", balance: 0, api_token: [FILTERED]>
2.7.3 :007 > c = Company.find 1
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
Models source code:
class Recipient < ApplicationRecord
validates :phone, presence: true, uniqueness: { scope: :callout_id }
validates :code, presence: true, uniqueness: true
belongs_to :company
belongs_to :callout
before_validation :generate_code
private
# Generates unique code for every recipient
# because phone column can't be unique
def generate_code
if self.code.nil?
self.code = Recipient.make_code self.phone, self.callout_id, self.payload
end
end
end
class Callout < ApplicationRecord
belongs_to :company
has_many :recipients, dependent: :destroy
validates :company_id, presence: true
validates :name, presence: true
scope :auto_queue, -> { where(auto_queue: true ) }
end
class Company < ApplicationRecord
before_validation :generate_token!
has_many :callouts, dependent: :destroy
has_many :recipients, dependent: :destroy
has_many :user_companies, dependent: :destroy
has_many :users, through: :user_companies
has_many :invoices, dependent: :destroy
has_many :balance_logs, dependent: :destroy
validates :name, presence: true
def generate_token!
if api_token.nil?
update! api_token: SecureRandom.hex
end
end
end
That's related to some unexpected issue related to the use of --nomultiline or IRB.conf[:USE_MULTILINE] = false inside .irbrc file.
Similar issue with the hack
To avoid that issue, you can just skip using --nomultiline option, when launching your rails console.
bundle exec rails c -e production
A quick one-off solution if you mostly want --nomultiline behavior and/or just don't want to mess with configs:
x = string_with_weird_characters; nil
I have models Favorite_Photo, User, and Photo
In Heroku Console:
u = User.find(1)
u.favorites.last
=> #<Photo id: 37, user_id: 1, picture: "th.jpeg", title: "Cookies & Cream Pocky ", description: nil, photo_type: nil, location_type: nil, remote_picture_url: nil, created_at: "2016-07-07 03:04:03", updated_at: "2016-07-07 03:04:03">
And If I query:
u = User.find(1)
u.favorite_photos.last
=> #<FavoritePhoto id: 87, photo_id: 12, user_id: 1, created_at: "2016-07-07 19:37:28", updated_at: "2016-07-07 19:37:28">
class User
has_many :favorite_photos
has_many :favorites, through: :favorite_photos, source: :photo
class Photo
has_many :favorite_photos
has_many :favorited_by, through: :favorite_photos, source: :user
class FavoritePhoto
belongs_to :user
belongs_to :photo
validates :user_id, uniqueness: {
scope: [:photo_id],
message: 'can only favorite an item once'
}
UsersController
def show
#user = User.find(params[:id])
#favorites = #user.favorites
end
This returns a list of favorites ordered by photo_id. I want to create a scope that will order the favorites based on FavoritePhoto id:
has_many :favorites, -> { order("favorite_photos.id ASC") }, through: :favorite_photos, source: :photo
reference: scopes for has_many
I`m trying to use String as Primary/Foreign key on a small crawler that I'm making. But I keep receiving the following error when I try to use the Associations methods (eg.: a.crawler_details - Where a is an object called Asin):
RangeError: 8532503039 is out of range for ActiveRecord::Type::Integer with limit 4
Record example:
#<Asin asin: "8532503039", title: "O FĂsico", image_url: nil, active: false, created_at: "2015-05-04 03:30:29", updated_at: "2015-05-04 03:30:36">
Here are the details:
2.1.2 :001 > Asin.new
=> #<Asin asin: nil, title: nil, image_url: nil, active: true, created_at: nil, updated_at: nil>
2.1.2 :002 > CrawlerDetail.new
=> #<CrawlerDetail id: nil, amazon_price: nil, feed_price: nil, first_place: nil, second_place: nil, third_place: nil, fp_price: nil, sp_price: nil, tp_price: nil, run: nil, created_at: nil, updated_at: nil>
class Asin < ActiveRecord::Base
has_many :crawler_details, :foreign_key => 'id', :primary_key=> 'asin'
self.primary_key = 'asin'
...
end
class CrawlerDetail < ActiveRecord::Base
has_one :asin, :foreign_key => 'asin', :primary_key => 'id'
end
I also tried the belongs_to relation but with no luck. Any ideas here?
I think that is not association error , did you defined field name "asin" type integer in your database table ?
it may help please try to alter your database table from type integer to string .
Here's my self referential model and it's two join tables:
class Discourse < ActiveRecord::Base
belongs_to :forum
belongs_to :user
has_many :impressions
has_many :discourse_replies
has_many :replies, through: :discourse_replies
has_many :reply_retorts
has_many :retorts, through: :reply_retorts
end
class DiscourseReply < ActiveRecord::Base
belongs_to :discourse
belongs_to :reply, class_name: 'Discourse', foreign_key: 'reply_id'
end
class ReplyRetort < ActiveRecord::Base
belongs_to :reply
belongs_to :retort, class_name: 'Discourse', foreign_key: 'retort_id'
end
It seems to be working well...I can do this in the rails console:
2.0.0p247 :044 > fd = Discourse.create(title: 'first', body: 'first')
=> #<Discourse id: 139, user_id: nil, title: "first", body: "first", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:38:06", updated_at: "2014-04-07 20:38:06", forum_id: nil>
2.0.0p247 :046 > fdr = fd.replies.create(title: 'second relpy to first', body: 'second reply to first')
=> #<Discourse id: 141, user_id: nil, title: "second relpy to first", body: "second reply to first", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:38:51", updated_at: "2014-04-07 20:38:51", forum_id: nil>
2.0.0p247 :047 > fdrr = fdr.retorts.create(title: 'a reply to a reply', body: 'a reply to a reply')
=> #<Discourse id: 142, user_id: nil, title: "a reply to a reply", body: "a reply to a reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:27", updated_at: "2014-04-07 20:39:27", forum_id: nil>
2.0.0p247 :048 > fdrrr = fdrr.retorts.create(title: 'a reply to a reply to a reply', body: 'a reply to a reply reply')
=> #<Discourse id: 143, user_id: nil, title: "a reply to a reply to a reply", body: "a reply to a reply reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:47", updated_at: "2014-04-07 20:39:47", forum_id: nil>
2.0.0p247 :050 > fdr.retorts
=> #<ActiveRecord::Associations::CollectionProxy [#<Discourse id: 142, user_id: nil, title: "a reply to a reply", body: "a reply to a reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:27", updated_at: "2014-04-07 20:39:27", forum_id: nil>]>
However, I need to find out the parent association, but can't figure out how to do it:
2.0.0p247 :053 > fdr.discourse # I want this to return the 'fd' instance
NoMethodError: undefined method `discourse` for #<Discourse:0x00000007080eb0>
2.0.0p247 :055 > fdrrr.reply # I want this to return the 'fdrr' instance
NoMethodError: undefined method `reply` for #<Discourse:0x000000070db860>
2.0.0p247 :055 > fdrrr.parent # I want this to return the 'fdrr' instance
NoMethodError: undefined method `parent' for #<Discourse:0x0000000672b428>
2.0.0p247 :055 > fdrrr.parent.try(:id) # I want this to return the 'fdrr' instance
NoMethodError: undefined method `parent' for #<Discourse:0x0000000672b428>
Nothing is working! However, if I were to set up polymorphic association STI, it work, right? As a nooby this is a bit difficult, especially on such a complex self-referential model, but the answer boils down to this:
What columns to I need to add to my discourses table
and
How should I tweak my relationships?
class Discourse < ActiveRecord::Base
belongs_to :forum
belongs_to :user
has_many :impressions
has_many :discourse_replies
has_many :replies, through: :discourse_replies
has_many :reply_retorts
has_many :retorts, through: :reply_retorts
end
I does not find self-referencing relationship in model 'Discourse'.
Here's my self referential model and it's two join tables:
class Discourse < ActiveRecord::Base
belongs_to :forum
belongs_to :user
has_many :impressions
has_many :discourse_replies
has_many :replies, through: :discourse_replies
has_many :reply_retorts
has_many :retorts, through: :reply_retorts
end
class DiscourseReply < ActiveRecord::Base
belongs_to :discourse
belongs_to :reply, class_name: 'Discourse', foreign_key: 'reply_id'
end
class ReplyRetort < ActiveRecord::Base
belongs_to :reply
belongs_to :retort, class_name: 'Discourse', foreign_key: 'retort_id'
end
It seems to be working well...I can do this in the rails console:
2.0.0p247 :044 > fd = Discourse.create(title: 'first', body: 'first')
=> #<Discourse id: 139, user_id: nil, title: "first", body: "first", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:38:06", updated_at: "2014-04-07 20:38:06", forum_id: nil>
2.0.0p247 :046 > fdr = fd.replies.create(title: 'second relpy to first', body: 'second reply to first')
=> #<Discourse id: 141, user_id: nil, title: "second relpy to first", body: "second reply to first", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:38:51", updated_at: "2014-04-07 20:38:51", forum_id: nil>
2.0.0p247 :047 > fdrr = fdr.retorts.create(title: 'a reply to a reply', body: 'a reply to a reply')
=> #<Discourse id: 142, user_id: nil, title: "a reply to a reply", body: "a reply to a reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:27", updated_at: "2014-04-07 20:39:27", forum_id: nil>
2.0.0p247 :048 > fdrrr = fdrr.retorts.create(title: 'a reply to a reply to a reply', body: 'a reply to a reply reply')
=> #<Discourse id: 143, user_id: nil, title: "a reply to a reply to a reply", body: "a reply to a reply reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:47", updated_at: "2014-04-07 20:39:47", forum_id: nil>
2.0.0p247 :050 > fdr.retorts
=> #<ActiveRecord::Associations::CollectionProxy [#<Discourse id: 142, user_id: nil, title: "a reply to a reply", body: "a reply to a reply", deleted: nil, delete_date: nil, created_at: "2014-04-07 20:39:27", updated_at: "2014-04-07 20:39:27", forum_id: nil>]>
However, I need to find out the parent association, but can't figure out how to do it:
2.0.0p247 :053 > fdr.discourse # I want this to return the 'fd' instance
NoMethodError: undefined method `discourse` for #<Discourse:0x00000007080eb0>
2.0.0p247 :055 > fdrrr.reply # I want this to return the 'fdrr' instance
NoMethodError: undefined method `reply` for #<Discourse:0x000000070db860>
2.0.0p247 :055 > fdrrr.parent # I want this to return the 'fdrr' instance
NoMethodError: undefined method `parent' for #<Discourse:0x0000000672b428>
2.0.0p247 :055 > fdrrr.parent.try(:id) # I want this to return the 'fdrr' instance
NoMethodError: undefined method `parent' for #<Discourse:0x0000000672b428>
Nothing is working!
class Discourse < ActiveRecord::Base
def reply
DiscourseReply.where(reply_id: id).first.try(:discourse) ||
ReplyRetort.where(retort_id: id).first.try(:reply)
end
alias_method :parent, :reply
alias_method :discourse, :reply
end
But you might want to store the id of the parent on the Discourse model, and maybe have Discourse by polymorphic (using STI)? I feel like it's weird not to be able to tell the type of the object without looking at the associations.