Get parent object via a through table - ruby-on-rails

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.

Related

How to group ruby array based on id in the hash

I have two models post and topic which has a one to many relation
#Post.rb
class Post < ApplicationRecord
belongs_to :topic
validates :topic_id, presence: true
validates :title, presence: true
validates :body, presence: true
end
if i have an array of posts by calling Post.all for example
#<ActiveRecord::Relation [#<Post id: 1, title: "Rails Code", body: "class TopicsController < ApplicationController\r\n ...", created_at: "2018-05-22 09:34:15", updated_at: "2018-05-22 09:34:15", topic_id: "2">,
#<Post id: 2, title: "Post with tags", body: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq...", created_at: "2018-05-22 11:48:54", updated_at: "2018-05-22 11:48:54", topic_id: "2">,
#<Post id: 3, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:02", updated_at: "2018-05-23 12:54:02", topic_id: "2">,
#<Post id: 4, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:09", updated_at: "2018-05-23 12:54:09", topic_id: "1">,
#<Post id: 5, title: "12hellsdssdo world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:15", updated_at: "2018-05-23 12:54:15", topic_id: "1">]>
is there a way i could group them by their topic_id so i could display them topic by topic
example
Topic - 1
post 1 post2 post 3
Topic -2
post4 post5
Use this:
Post.all.group_by(&:topic_id).each do |topic_id, posts|
...
end
Found the answer.
You can do it using ruby's Enumerable#group_by:
post.group_by{|post| post.topic_id}

Use string as PK and FK on Rails 4

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 .

Create instance through self referential association

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.

Create a polymorphic STI association

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'.

.first returning wrong object type

If you look at the four method calls below, Service.first returns a Service object, Salon.first returns a Salon object, etc. But TransactionItem.first returns a Service object. Why could this be?
ruby-1.8.7-p334 :001 > Service.first
=> #<Service id: 147, name: "Fub", salon_id: 2, created_at: "2011-08-10 18:00:07", updated_at: "2011-08-10 18:00:12", price: nil, active: true, archived: true>
ruby-1.8.7-p334 :002 > Salon.first
=> #<Salon id: 1, name: "The Cheeky Strut", created_at: nil, updated_at: nil, address_id: nil, email: nil>
ruby-1.8.7-p334 :003 > Product.first
=> #<Product id: 1, name: "Herbal Essences Shampoo", retail_price: #<BigDecimal:10305f1f0,'0.1E2',9(18)>, wholesale_price: nil, sku: "", salon_id: 2, created_at: "2011-07-08 01:35:48", updated_at: "2011-07-08 01:35:48", archived: false>
ruby-1.8.7-p334 :004 > TransactionItem.first
=> #<Service id: 63, created_at: "2011-08-30 20:05:57", updated_at: "2011-08-30 20:05:57", price: #<BigDecimal:10303eba8,'0.18E2',9(18)>>
ruby-1.8.7-p334 :005 >
This is what my app/models/transaction_item.rb looks like:
class TransactionItem < ActiveRecord::Base
belongs_to :transaction
belongs_to :stylist
end
I blew away the TransactionItem table via a migration, then created a brand new migration to re-create it. That seems to have fixed the problem.

Resources