How to fetch objects in joins? - mysql

This is my schema :
Mention.rb
belongs_to :user
create_table "mentions", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "mentionable_id", limit: 4
t.string "mentionable_type", limit: 191
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "deleted_at"
end
User.rb
No Association.
Query:
mentions = Mention.joins(:user).where(mentions: {mentionable_type: 'Comment', mentionable_id: #comments_ids}).select('users.*, mentions.mentionable_id AS comment_id').group_by(&:comment_id)
Output :
=> {155=>
[#<Mention:0x00007ff51a309de8 id: 110, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>,
#<Mention:0x00007ff51a3092f8 id: 112, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>],
156=>[#<Mention:0x00007ff51a3098e8 id: 111, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>]}
id:110 that is here in the output is of user and 115 is mentionable_id.
How can I get complete user object with group_by mentionable_id ?
Expected:
=> {155=>
[#<User:0x00007ff51a309de8 id: 110, name: "abc", email: 'xyz#mail.com', deleted_at: nil>,
#<User:0x00007ff51a3092f8 id: 112, name: "abc", email: 'xyz#mail.com', deleted_at: nil>],
156=>[#<User:0x00007ff51a3098e8 id: 111, name: "abc", email: 'xyz#mail.com', deleted_at: nil>]}

You need to query through User:
User.joins(:mentions)
.where(mentions: { mentionable_type: 'Comment', mentionable_id: #comments_ids })
.select('users.*, mentions.mentionable_id AS comment_id')
.group_by(&:comment_id)

Related

Laravel Subquery Value From hasmany Relation Value

I have a model
Logbook and a model
LogbookEntries
Logbook hasMany LogbookEntries and LogbookEntries belongsto Logbook (out of the scope of the question though). In my LogbookEntries I have two fields (plus others): start date and end_date. I want to show all LogbookEntries which the following date entry as an example.
ENTRY 1
start_date: 01 Mar 19
end_date: 05 Mar 19
ENTRY 2
start_date: 06 Mar 19
end_date: 12 Mar 19
ENTRY 3
start_date: 19 Jun 19
end_date: 22 Jun 19
If I say show all which have a follow-up date, then only Entry 3 will display. My issue is:
Logbook::whereHas('LogbookEntries', function($q) {
$q->where('start_date', <???.end_date + 1 day>)
})
This worked for me:
If I understand your question correctly then I think the easiest way to achieve this would be with the following:
Note the use of whereraw instead of where so that we can use direct
mySql code
Logbook::whereHas('LogbookEntries', function($q) {
$q->whereraw('date_format(date(end_date),"%Y-%m-%d") = date_format(date(start_date),"%Y-%m-%d") + interval 1 day')
})
I tested this on my system and it worked a charm. However, my timestamps were in the format Y-m-d HH:mm:ii so I needed the date_format to change them. You may not need this. Therefore, you may want to also try the following:
Logbook::whereHas('LogbookEntries', function($q) {
$q->whereraw('date(end_date) = date(start_date) + interval 1 day')
})
As this would be a lot tidier.
Basically what we are doing is getting entries where the end_date is the same as the start_date + 1 day. You were close but just not quite there.
My system so you can see it working:
Without the whereraw statement:
>>> Task::Select('start_date','end_date')->get();
=> Illuminate\Database\Eloquent\Collection {#3325
all: [
App\Task {#3307
start_date: "2018-12-20 08:00:00",
end_date: null,
},
App\Task {#3291
start_date: "2018-12-18 00:00:00",
end_date: "2018-12-19 00:00:00",
},
App\Task {#3318
start_date: "2018-12-19 00:00:00",
end_date: "2019-01-03 00:00:00",
},
App\Task {#3319
start_date: "2018-12-20 00:00:00",
end_date: "2018-12-21 00:00:00",
},
App\Task {#3310
start_date: "2018-12-20 00:00:00",
end_date: "2018-12-21 00:00:00",
},
App\Task {#3317
start_date: "2018-12-20 14:43:16",
end_date: "2018-12-21 14:43:16",
},
App\Task {#3316
start_date: "2018-12-20 14:45:27",
end_date: "2018-12-27 14:45:27",
},
App\Task {#3315
start_date: "2018-12-20 14:46:48",
end_date: "2018-12-24 14:46:48",
},
App\Task {#3313
start_date: "2018-12-21 09:25:24",
end_date: "2018-12-24 09:25:24",
},
App\Task {#3298
start_date: "2019-01-02 08:10:19",
end_date: "2019-01-16 08:10:19",
},
],
}
With the whereraw statement:
>>> Task::Select('start_date','end_date')->whereraw('date_format(date(end_date),"%Y-%m-%d") = date_format(date(start_dat
e),"%Y-%m-%d") + interval 1 day')->get();
=> Illuminate\Database\Eloquent\Collection {#3314
all: [
App\Task {#3312
start_date: "2018-12-18 00:00:00",
end_date: "2018-12-19 00:00:00",
},
App\Task {#3309
start_date: "2018-12-20 00:00:00",
end_date: "2018-12-21 00:00:00",
},
App\Task {#3320
start_date: "2018-12-20 00:00:00",
end_date: "2018-12-21 00:00:00",
},
App\Task {#3329
start_date: "2018-12-20 14:43:16",
end_date: "2018-12-21 14:43:16",
},
],
}

Nested Joins in Rails

I have 3 models Company, User, Loan in my Rails application
company.rb
class Company < ApplicationRecord
has_many :users
end
Company id: 1, name: "A", created_at: "2018-02-06 07:34:17", updated_at: "2018-02-06 07:34:17"
Company id: 2, name: "B", created_at: "2018-02-06 07:34:19", updated_at: "2018-02-06 07:34:19"
Company id: 3, name: "C", created_at: "2018-02-06 07:34:21", updated_at: "2018-02-06 07:34:21"
user.rb
class User < ApplicationRecord
belongs_to :company
has_many :loans
end
User id: 1, name: "Sachin", company_id: 1, created_at: "2018-02-06 07:35:53", updated_at: "2018-02-06 08:02:41", user_status: true
User id: 2, name: "Ghanshyam", company_id: 1, created_at: "2018-02-06 07:36:01", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 3, name: "Anand", company_id: 1, created_at: "2018-02-06 07:36:06", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 4, name: "Ghanshyam Rahul", company_id: 1, created_at: "2018-02-06 07:36:15", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 5, name: "Anand", company_id: 3, created_at: "2018-02-06 07:43:56", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 6, name: "Ghanshyam", company_id: 3, created_at: "2018-02-06 07:43:58", updated_at: "2018-02-06 08:02:41", user_status: false
loan.rb
class Loan < ApplicationRecord
belongs_to :user
end
Loan id: 1, name: "loan 1", user_id: 1, created_at: "2018-02-06 07:44:46", updated_at: "2018-02-06 07:44:46"
Loan id: 5, name: "loan 5", user_id: 1, created_at: "2018-02-06 07:44:54", updated_at: "2018-02-06 07:44:54"
Loan id: 6, name: "loan 6", user_id: 6, created_at: "2018-02-06 07:45:33", updated_at: "2018-02-06 07:45:33"
Loan id: 7, name: "loan 7", user_id: 6, created_at: "2018-02-06 07:45:34", updated_at: "2018-02-06 07:45:34"
Loan id: 8, name: "loan 8", user_id: 6, created_at: "2018-02-06 07:45:36", updated_at: "2018-02-06 07:45:36"
I want to write down join query(single query) that fetch list of company if there users have any loan like follows :
Company id: 1, name: "A", created_at: "2018-02-06 07:34:17", updated_at: "2018-02-06 07:34:17"
Company id: 3, name: "C", created_at: "2018-02-06 07:34:21", updated_at: "2018-02-06 07:34:21"
Company.joins(users: [:loans]).group('companies.id')
To avoid possible company duplications I would group companies table by company id field.
Company.joins(users: :loans).distinct
Will give you all companies that have users with loan
You create join query that will join company with their users, and give you companies with users, and then join users with their loans. As it is using inner join, when users do not have company they do not appear and their companies do not appear either

Convert numerical month to string using ionic 2 Pipe

How can I convert month to string in ionic 2 using Pipe? given the sample data below:
In my .ts file
let users = [
{
user: "A",
birthDate: "2017-08-01"
},
{
user: "B",
birthDate: "2017-08-02"
},
{
user: "C",
birthDate: "2017-08-03"
},
{
user: "D",
birthDate: "2017-08-04"
}
]
In my .html file
<ion-list>
<ion-item *ngFor="let user of users">
<div>Name: {{user.name}}</div>
<div>Birth Date: {{user.birthDate | date: "MM dd, yyyy"}}</div>
</ion-item>
</ion-list>
The sample output will be
Name: A
Birth Date: 08 01, 2017
Name: B
Birth Date: 08 02, 2017
Name: C
Birth Date: 08 03, 2017
Name: D
Birth Date: 08 04, 2017
Expected output will be
Name: A
Birth Date: August 01, 2017
Name: B
Birth Date: August 02, 2017
Name: C
Birth Date: August 03, 2017
Name: D
Birth Date: August 04, 2017
How can I achieve expected output?
Use MMMM instead of MM
<ion-list>
<ion-item *ngFor="let user of users">
<div>Name: {{user.name}}</div>
<div>Birth Date: {{user.birthDate | date: "MMMM dd, yyyy"}}</div>
</ion-item>
</ion-list>

Selecting all the records from table to which given number belongs to

Suppose I have following three records in my model :
#<Rda:0xf6e8a0c
id: 1,
age_group: "18-100",
weight: "60",
nutrient: "energy(kcal/day)",
value: "2730",
created_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00,
updated_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00>
#<Rda:0xf6e8a0c
id: 2,
age_group: "10-15",
weight: "60",
nutrient: "energy(kcal/day)",
value: "2730",
created_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00,
updated_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00>
#<Rda:0xf6e8a0c
id: 3,
age_group: "20-100",
weight: "60",
nutrient: "energy(kcal/day)",
value: "2730",
created_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00,
updated_at: Sat, 15 Oct 2016 08:21:43 UTC +00:00>
Now, I want to get all those records in which my given value falls in a 'age_group' columns ranges. For example: suppose my age is 25 then I should get records with ids 1 & 3 from the above records because '25' falls in between '18-100' and '20-100'
You might do
def self.foo(age)
all.select { |rda| Range.new(*rda.age_group.split('-').map(&:to_i)).cover? age }
end

update_attributes failing when I try to update an attribute

I have a user database as User(id: integer, username: string, created_at: datetime, updated_at: datetime, password_digest: string, admin: boolean, usermanager: boolean).
I want to update an user and make him Admin, setting the admin varaible to true.
My update in the controller:
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "User edited"
redirect_to current_user
else
render users_url
end
end
The update_attributes is failing in all cases. I opened a debugger and tried to call update_attributes, it is failing there as well.
(byebug) user_params = {"admin"=>true}
{"admin"=>true}
(byebug) #user
#<User id: 1, username: "dsmegha", created_at: "2015-09-11 07:42:01", updated_at: "2015-09-13 03:25:01", password_digest: "$2a$10$BInH6J1dXHanqNIdGag6megSyrmm95AmjTEGPemNdGU...", admin: false, usermanager: nil>
(byebug) #user.update_attributes(user_params)
(0.2ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."username" = 'dsmegha' AND "users"."id" != 1) LIMIT 1
(0.2ms) rollback transaction
false
The update_attribute works for the same.
(byebug) #user.update_attribute(:admin,true)
(0.2ms) begin transaction
(0.1ms) commit transaction
true
(byebug) #user
#<User id: 1, username: "dsmegha", created_at: "2015-09-11 07:42:01", updated_at: "2015-09-13 03:25:01", password_digest: "$2a$10$BInH6J1dXHanqNIdGag6megSyrmm95AmjTEGPemNdGU...", admin: true, usermanager: nil>
(byebug)
Any idea what I am missing here?
Maybe I think current user data is invalid. please check user.errors.
example)
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,:confirmable,
:recoverable, :rememberable, :trackable, :validatable, :lockable
validates :name, presence: true
end
pry
pry(main)> user = User.last
=> #<User:0x007fe328fe56d8
id: 3,
email: "hogehoge#example.com",
name: "",
encrypted_password: "$2a$10$I.xXo0AtAz8nuCUzOGclPe6PA//XMZtjW6fh94D1t25jb7eV9bsS.",
current_sign_in_at: Tue, 02 Jun 2015 01:53:08 JST +09:00,
last_sign_in_at: Tue, 02 Jun 2015 01:52:20 JST +09:00,
current_sign_in_ip: "127.0.0.1",
last_sign_in_ip: "127.0.0.1",
created_at: Tue, 02 Jun 2015 01:49:40 JST +09:00,
updated_at: Sun, 13 Sep 2015 13:16:26 JST +09:00,
confirmation_token: nil,
confirmed_at: Tue, 02 Jun 2015 01:52:01 JST +09:00,
confirmation_sent_at: Tue, 02 Jun 2015 01:49:40 JST +09:00,
unconfirmed_email: nil,
failed_attempts: 0,
unlock_token: nil,
locked_at: nil,
status: 1>
[7] pry(main)> user.update_attributes(status: 2)
(0.1ms)
BEGIN
(0.2ms)
ROLLBACK
=> false
[8] pry(main)> user.errors
=> #<ActiveModel::Errors:0x007fe328d893f8
#base=
#<User:0x007fe328fe56d8
id: 3,
email: "hogehoge#example.com",
name: "",
encrypted_password: "$2a$10$I.xXo0AtAz8nuCUzOGclPe6PA//XMZtjW6fh94D1t25jb7eV9bsS.",
reset_password_token: "XWmjsEBujb2-aWd5YHYT",
reset_password_sent_at: nil,
remember_created_at: nil,
sign_in_count: 2,
current_sign_in_at: Tue, 02 Jun 2015 01:53:08 JST +09:00,
last_sign_in_at: Tue, 02 Jun 2015 01:52:20 JST +09:00,
current_sign_in_ip: "127.0.0.1",
last_sign_in_ip: "127.0.0.1",
created_at: Tue, 02 Jun 2015 01:49:40 JST +09:00,
updated_at: Sun, 13 Sep 2015 13:16:26 JST +09:00,
confirmation_token: nil,
confirmed_at: Tue, 02 Jun 2015 01:52:01 JST +09:00,
confirmation_sent_at: Tue, 02 Jun 2015 01:49:40 JST +09:00,
unconfirmed_email: nil,
failed_attempts: 0,
unlock_token: nil,
locked_at: nil,
status: 2>,
#messages={:name=>["can't be blank"]}>
additionally write.
View has password input field perhaps? In that case, I think you need to delete passward params when update user data.
How about this?
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,:confirmable,
:recoverable, :rememberable, :trackable, :validatable, :lockable
validates :name, presence: true
def update_without_current_password(params, *options)
params.delete(:current_password)
if params[:password].blank?
params.delete(:password)
params.delete(:password_confirmation) if params[:password_confirmation].blank?
end
clean_up_passwords
update_attributes(params, *options)
end
end
controller
def update
#user = User.find(params[:id])
if #user.update_without_current_password(user_params)
flash[:success] = "User edited"
redirect_to current_user
else
render users_url
end
end