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
Related
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
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
I want to constraint scope of attachments to current_user attachments or attachments that are not yet assigned to comment, to be able to find later
Attachment has_one :comment, optional: true
Attachment has_one :user, through :comment, comment - through task, task - through project
> user.attachments.to_sql
=> "SELECT \"attachments\".* FROM \"attachments\" INNER JOIN \"comments\" ON \"attachments\".\"comment_id\" = \"comments\".\"id\" INNER JOIN \"tasks\" ON \"comments\".\"task_id\" = \"tasks\".\"id\" INNER JOIN \"projects\" ON \"tasks\".\"project_id\" = \"projects\".\"id\" WHERE \"projects\".\"user_id\" = $1 ORDER BY \"comments\".\"created_at\" ASC, tasks.position"
How to make it work
> user.attachments.or(Attachment.where(comment_id: nil))
Relation passed to #or must be structurally compatible. Incompatible values: [:order, :joins, :references]
I have tried
without_comment = Attachment.joins(comment: [task: [:project]]).where(comment_id: nil).order('"comments"."created_at" ASC, tasks.position')
user.attachments.or(without_comment)
[35] pry(#<AttachmentResource>)> without_comment.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 \"attachments\".\"comment_id\" IS NULL ORDER BY \"comments\".\"created_at\" ASC, tasks.position"
[36] pry(#<AttachmentResource>)> user.attachments.or(without_comment)
ArgumentError: Relation passed to #or must be structurally compatible. Incompatible values: [:order, :joins, :references]
from /home/bjorn/.rvm/gems/ruby-2.4.1#ngrx-todolist/gems/activerecord-5.1.1/lib/active_record/relation/query_methods.rb:655:in `or!'
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>]
Thanks to #fanta
class AttachmentPolicy < ApplicationPolicy
class Scope < Scope
def resolve
# user can see his attachments and attachments without owner
Attachment
.left_outer_joins(comment: [task: [:project]])
.where('projects.user_id = ? OR comment_id IS NULL', user.id)
end
end
def update?
# if attachment doesnt have owner - anyone can change it
record.comment.nil? ? true : owner?
end
end
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 got this model:
[#<Account:0x007fcf32153098
id: 1,
profit: 100,
user_id: 1,
created_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00,
updated_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00>,
#<Account:0x007fcf32152df0
id: 2,
profit: 500,
user_id: 1,
created_at: Sun, 16 Nov 2015 15:05:07 UTC +00:00,
updated_at: Sun, 15 Nov 2015 15:05:07 UTC +00:00>,
]
And for now I got this to group them in date:
Account.all.group_by{|a| a.created_at.strftime("%Y-%m-%d")}
{"2015-11-15"=>
[#<Account:0x007fcf3247b1a8
id: 1,
profit: 100,
user_id: 1,
created_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00,
updated_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00>],
"2015-11-16"=>
[#<Account:0x007fcf3247afc8
id: 2,
profit: 500,
user_id: 1,
created_at: Sun, 16 Nov 2015 15:05:07 UTC +00:00,
updated_at: Sun, 15 Nov 2015 15:05:07 UTC +00:00>]}
My question is: How can I group them and at the same time sum the profit together if there are more than one record for that day? Seems like I can't use sum(:profit) with postgres?
I think you can just do this simply with:
Account.order("DATE(created_at)").group("DATE(created_at)").sum(:profit)