I'd like to display in rails console all the collections of the parent entity "Article", which would be a relationship between itself, example:
# article.rb
class Article < ActiveRecord::Base
belongs_to :parent, :class_name => 'Article', optional: true
has_many :sub_articles, :class_name => 'Article', :foreign_key => 'parent_id'
end
Now what I have is:
irb(main):095:0> Article.find(1)
Article Load (0.9ms) SELECT "articles".* FROM "articles" ORDER BY
"articles"."id" ASC LIMIT $1 [["LIMIT", 1]]
=>
#<Articles:0x0000264231faa292
id: 1,
name: "king article"
created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
parent_id: nil
What I'd like to display on the rails console:
id: 1,
name: "king article"
created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
parent_id: nil
sub_articles:
[ Article:0x0000641428defb71
id: 2,
name: "pencils article"
created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
parent_id: 1
sub_articles:
[ Article:0x0000621438defb71
id: 3,
name: "pencil child 1"
created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
parent_id: 2
sub_articles: [],
id: 4,
name: "pencil child 2"
created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
parent_id: 2
sub_articles: []
]
]
Ultimately what I am looking for is if a parent is consulted to show their children (and the children of the children if possible)
It's probably best achieved by calling to_json on the top-level article, and configuring the as_json method of Article to include sub_articles
class Article < ActiveRecord::Base
def as_json(options={})
super(methods: [:subarticles])
end
end
in the rails console:
$> Article.find(3).to_json # => should give you the hierarchy you're looking for
Related
I am building a RestAPI using Rails 5. I have 3 tables currently
Members
ContactSource (name)
ContactSourceMemberMap (member_id, contact_source_id, value)
Where,
class ContactSourceMemberMap < ApplicationRecord
belongs_to :member
belongs_to :contact_source
end
Now I want to fetch name from ContactSource and value from ContactSourceMemberMap.
I tried:
ContactSource.eager_load(:contact_source_member_maps).select("contact_sources.name", "contact_source_member_maps.value")
on ContactSourceMemberMap model.
The SQL which is getting generating is fetching data by performing INNER JOIN. But on the rails end its coming like
[#<ContactSource:0x007fa14f261950
id: 1,
name: "ContactSource1",
created_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00,
updated_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00>,
#<ContactSource:0x007fa14f200290
id: 2,
name: "ContactSource2",
created_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00,
updated_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00>,
#<ContactSource:0x007fa14fa8fb18
id: 3,
name: "ContactSource3",
created_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00,
updated_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00>,
#<ContactSource:0x007fa14fa8f2d0
id: 4,
name: "ContactSource4",
created_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00,
updated_at: Thu, 08 Mar 2018 16:33:00 UTC +00:00>]}]
It is not displaying the value field. Any thoughts why is it behaving like that?
contact_sources = ContactSource.eager_load(:contact_source_member_maps).select("contact_sources.name", "contact_source_member_maps.value")
and then you can get the other object with
contact_sources.first.contact_source_member_maps
if I am wrong you can check the following guide
I have 3 courses A(july 1), B(july 2), C(july 3).A and B is rated 4 and C is rated 5.
I want to order the course like this
C should come first because it was created latest and it has higher rating than others.
A should come second because it was created first than B
I cant use order because it wont give me what i need. any way to fix this?
Here is how i am fetching the data
#courses.order('updated_at DESC, average_rating DESC')
code
[
#<Course:0x00000009f3c128
id: 6,
tutor_id: 2,
course_name: "name",
course_subtitle: "sub",
course_description: "<p>test</p> test\r\n",
video_link: "https://www.youtube.com/watch?v=UVrQcieqD0U",
course_language: "German",
course_image: "finalse.png",
created_at: Tue, 11 Jul 2017 05:03:03 UTC +00:00,
updated_at: Tue, 11 Jul 2017 08:47:03 UTC +00:00,
status: "accepted",
average_rating: 2.5,
rated_time: nil>,
#<Course:0x00000008139608
id: 7,
tutor_id: 2,
course_name: "another",
course_subtitle: "another subtuitle",
course_description: "<p>course descrition</p>\r\n",
video_link: "https://www.youtube.com/watch?v=uaTeZA-Gj7s",
course_language: "Chinese",
course_image: nil,
created_at: Tue, 11 Jul 2017 10:40:45 UTC +00:00,
updated_at: Tue, 11 Jul 2017 10:41:06 UTC +00:00,
status: "accepted",
average_rating: 2.5,
rated_time: nil>,
#<Course:0x0000000813bea8
id: 8,
tutor_id: 2,
course_name: "asfas",
course_subtitle: "were",
course_description: "<p>asdfsadf</p>\r\n",
video_link: "https://www.youtube.com/watch?v=xGytDsqkQY8",
course_language: "English",
course_image: nil,
created_at: Wed, 12 Jul 2017 03:53:26 UTC +00:00,
updated_at: Wed, 12 Jul 2017 04:32:33 UTC +00:00,
status: "accepted",
average_rating: 1.0,
rated_time: nil>,
Try:
Course.all.order("average_rating DESC, created_at ASC")
try
Course.order({ created_at: :desc, rating: :desc })
This will sort first on created_at and if two records have same created_at the will sort on the basis of rating
Attachment has_one :comment, optional: true
Attachment has_one :user, through :comment, comment - through task, task - through project
I want to find all current_user attachments plus attachments without owner -> no parent comment
Query Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id) doesnt include attachments without comment, why?
[10] pry(#<CommentResource>)> Attachment.all
=> [#<Attachment:0x00000008a6f3a8
id: 1,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x00000008a6f268
id: 2,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x00000008a6f128
id: 3,
file: "attachments.rb",
comment_id: nil,
created_at: Sun, 21 May 2017 14:29:51 UTC +00:00,
updated_at: Sun, 21 May 2017 14:29:51 UTC +00:00>]
[11] pry(#<CommentResource>)> Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id).to_sql
=> "SELECT \"attachments\".* FROM \"attachments\" INNER JOIN \"comments\" ON \"comments\".\"id\" = \"attachments\".\"comment_id\" INNER JOIN \"tasks\" ON \"tasks\".\"id\" = \"comments\".\"task_id\" INNER JOIN \"projects\" ON \"projects\".\"id\" = \"tasks\".\"project_id\" WHERE (projects.user_id = 1 OR attachments.comment_id IS NULL)"
[12] pry(#<CommentResource>)> Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id)
=> [#<Attachment:0x0000000891c7a8
id: 1,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x0000000891c668
id: 2,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>]
The joins method on active record queries the records by using inner join, which means in your case it only returns attachments with comments. If you want to include attachments without comments, you need to left outer join.
http://guides.rubyonrails.org/active_record_querying.html#left-outer-joins
I have a table which will have possible duplicate records.
id: 24,
name: "vamsi",
mobile: "7639817688",
company: "digi",
requirement: "mobile app",
created_at: Wed, 12 Oct 2016 11:05:33 UTC +00:00,
updated_at: Wed, 12 Oct 2016 11:05:33 UTC +00:00,
email_sent: false>,
#<Contact:0x00000006d7a4f0
id: 25,
name: "vamsi",
mobile: "7639817688",
company: "digi",
requirement: "mobile app",
created_at: Wed, 12 Oct 2016 11:05:57 UTC +00:00,
updated_at: Wed, 12 Oct 2016 11:05:57 UTC +00:00,
email_sent: false>]
Now I would like to find the unique records on which email_sent is false. I have tried this
Contact.where(email_sent: false).distinct
Contact Load (0.4ms) SELECT DISTINCT "contacts".* FROM "contacts" WHERE "contacts"."email_sent" = $1 [["email_sent", false]]
=> [#<Contact:0x00000006a1a698
id: 25,
name: "vamsi",
mobile: "7639817688",
company: "digi",
requirement: "mobile app",
created_at: Wed, 12 Oct 2016 11:05:57 UTC +00:00,
updated_at: Wed, 12 Oct 2016 11:05:57 UTC +00:00,
email_sent: false>,
#<Contact:0x00000006a1a418
id: 24,
name: "vamsi",
mobile: "7639817688",
company: "digi",
requirement: "mobile app",
created_at: Wed, 12 Oct 2016 11:05:33 UTC +00:00,
updated_at: Wed, 12 Oct 2016 11:05:33 UTC +00:00,
email_sent: false>]
But I would not want 2 records, since both are same. I would like only one to be shown. Is there any way I can solve this.
First part, the model should have validations so that these kinds of data won't be stored
It can be done via this
validates_uniqueness_of :name, scope: [:mobile, :requirement, :company]
Second part, still if you want to query something like above scenario. You have to do this
Contact.select(:name, :company, :mobile, :requirement).where(email_sent: false).distinct would be the query
ps: Answer picked up from all the comments in the question
Try group by email_sent after using where:
Contact.where(email_sent: false).group(:email_sent)
I am using the ActiveModel::Dirty library. I have the following code:
def tasks_changed?
#changed = false
self.tasks.each do |task|
if task.previous_changes.any?
#changed = true
puts 'task changed so no update'
puts 'this task changed' + task.inspect.to_s
puts 'here are the changes' + task.previous_changes.to_s
end
end
return #changed
end
I a user changes something in a form, this method changes the behavior of the controller. The problem is that one of the fields is a datetime, and for some reason previous_changes thinks the datetime changes every time, regardless of whether or not it was changed.
The console is even telling me there are no changes. Here is what the puts statements above produce in the console:
task changed so no update
this task changed#<Task id: 19, title: "task 1", content: "task 2 content", created_at: "2014-03-11 17:33:26", updated_at: "2014-03-11 20:00:01", schedule_id: 1, amount: nil, time_frame: "2014-03-27 20:00:00", state: "incomplete", denied: 0, order_number: 0, finished_description: nil>
here are the changes{"time_frame"=>[Thu, 27 Mar 2014 16:00:00 EDT -04:00, Thu, 27 Mar 2014 16:00:00 EDT -04:00], "updated_at"=>[Tue, 11 Mar 2014 15:57:44 EDT -04:00, Tue, 11 Mar 2014 16:00:01 EDT -04:00]}
task changed so no update
this task changed#<Task id: 21, title: "task 2", content: "task 2 content", created_at: "2014-03-11 17:42:18", updated_at: "2014-03-11 20:00:01", schedule_id: 1, amount: nil, time_frame: "2014-03-29 20:00:00", state: "incomplete", denied: 0, order_number: 1, finished_description: nil>
here are the changes{"time_frame"=>[Sat, 29 Mar 2014 16:00:00 EDT -04:00, Sat, 29 Mar 2014 16:00:00 EDT -04:00], "updated_at"=>[Tue, 11 Mar 2014 15:57:44 EDT -04:00, Tue, 11 Mar 2014 16:00:01 EDT -04:00]}
task changed so no update
this task changed#<Task id: 22, title: "task 3 ", content: "change", created_at: "2014-03-11 18:43:23", updated_at: "2014-03-11 20:00:01", schedule_id: 1, amount: nil, time_frame: "2014-03-31 20:00:00", state: "incomplete", denied: 0, order_number: 2, finished_description: nil>
here are the changes{"time_frame"=>[Mon, 31 Mar 2014 16:00:00 EDT -04:00, Mon, 31 Mar 2014 16:00:00 EDT -04:00], "updated_at"=>[Tue, 11 Mar 2014 15:57:44 EDT -04:00, Tue, 11 Mar 2014 16:00:01 EDT -04:00]}
My basic question is why does previous_changes think that there is a change every time and how do I fix it?
At least the timeframe and the updated_at changed. Note the a time object holds more than just seconds and the inspect methods does not show milliseconds for example.
But nobody will be able to tell you why this happens without providing the code that does that.