How to get id from associated relation rails? - ruby

Can i get an id from associated relation?
for example i have relation between user and skill through user_skill
In User model, i write like this:
class User < ApplicationRecord
has_many ::skills, through: :user_skills
end
In UserSkill model
class UserSkill < ApplicationRecord
belongs_to :skill
belongs_to :user
end
I can call them like this
User.find(1).skills
but there is no user_skill id in there.
how to include id of user_skill? because everytime i call
User.find(1).skills
it will be like this
[#<Skill id: 3, name: "Google Analytics", description: "Google Analytics\r\n", created_at: "1970-01-04 11:20:00.000000000 +0000", updated_at: "1970-01-04 11:20:00.000000000 +0000", category: "software">, #<Skill id: 8, name: "Adobe After Effect", description: "Test", created_at: "2022-08-21 02:58:25.561498000 +0000", updated_at: "2022-08-21 02:58:25.561498000 +0000", category: "software">, #<Skill id: 1, name: "Microsoft Office", description: "Word, Excel, PowerPoint", created_at: "1970-01-02 03:46:40.000000000 +0000", updated_at: "1970-01-02 03:46:40.000000000 +0000", category: "software">]

You can do:
user_skills = User.find(1).user_skills.include(:skill)
user_skills.each do |user_skill|
user_skill.id #=> the user_skill id
user_skill.skill #=> the actual skill
end

Related

Laravel HasMany Relation is returning all models, not related ones

I'm using Laravel 5.5, I have a Movie model:
class Movie extends Model
{
public function comments(){
return $this->hasMany(Comment::class);
}
}
and a Comment model:
class Comment extends Model
{
public function movie(){
return $this->belongsTo(Movie::class);
}
}
I have a movie instance (stored in $movie variable):
id: "tt5726616",
title: "Call Me by Your Name",
original_title: "Call Me by Your Name",
rate: 4,
year: 2017,
length: "132",
language: "English, Italian, French, German",
country: "Italy, France, Brazil, USA",
director: "Luca Guadagnino",
created_at: "2018-01-21 15:28:31",
updated_at: "2018-01-21 15:28:31",
and I have 4 comments, 2 of them related to the corresponding movie:
all: [
App\Comment {#788
id: 1,
movie_id: "tt3967856",
author: "user1",
comment: "cool!",
rate: 2,
created_at: "2018-01-21 15:28:32",
updated_at: "2018-01-21 15:28:32",
},
App\Comment {#786
id: 2,
movie_id: "tt3967856",
author: "user2",
comment: "not bad!",
rate: 3,
created_at: "2018-01-21 15:28:32",
updated_at: "2018-01-21 15:28:32",
},
App\Comment {#785
id: 3,
movie_id: "tt5726616",
author: "user1",
comment: "cool!",
rate: 4,
created_at: "2018-01-21 15:28:32",
updated_at: "2018-01-21 15:28:32",
},
App\Comment {#784
id: 4,
movie_id: "tt5726616",
author: "user2",
comment: "not bad!",
rate: 5,
created_at: "2018-01-21 15:28:32",
updated_at: "2018-01-21 15:28:32",
},
],
the problem is, when I call $movie->comments, it returns all my 4 comments, not just those two with movie_id tt3967856. What should I do?
SOLVED:
I think that was because I was using string type for my primary and foreign keys. I changed ids to integer (I mean 1,2,... instead of "tt3967856" etc.) and everything worked fine :D
What if you specify foreign and local keys
class Movie extends Model
{
protected $casts=['movie_id'=>'integer'];
public function comments(){
return $this->hasMany(Comment::class,movie_id,id);
}
}
update:
I also noticed that movie_id has string type in comment object
You sbould cast it to integer

where for querying an array attribute in rails model

I have a user model with an array of roles.
u=User.first
u.roles = ['admin']
v=User.last
u.roles = ['admin', 'member']
How do i query to fetch all users with admin role?
Edit:
roles is a serialized array for the user model
User Model:
serialize :roles
Migration:
add_column :users, :roles, :string, default: []
Depends on what "roles" means:
If it is an association as in
class User < ActiveRecord::Base
has_many :roles
end
Then you look up the role and fetch all users:
Role.find_by_name("admin").users
or roles is just a column and it is serialised, in which case you can instantiate all users (slow)
User.all.select { |u| u.roles.include? "admin" }
Or query the database directly which is more complex and depends on the adapter.
My opinion: I would avoid using serialised columns, when relations can do. They are cumbersome in every way: Forms, Searches, Selects...
Another way is using scopes:
Model user.rb:
class User
scope :admins, -> () { where("roles #> ?", '{admin}')}
scope :by_roles, -> (roles) { where("roles #> ?", "{#{roles.join(', ')}}") }
end
Scoped calls, with results
Admins:
3.0.0 :001 > User.admins
User Load (0.4ms) SELECT "users".* FROM "users" WHERE (roles #> '{admin}') /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, account_uuid: "0812df2d-58ed-4231-aca5-ec7708a156bb", email: "admin#example.com", password_digest: [FILTERED], first_name: "Admin", last_name: "Admin" remember_token: nil, remember_token_expires_at: nil, roles: ["user", "admin"], created_at: "2021-12-02 11:51:50.684788000 +0000", updated_at: "2021-12-02 11:51:50.684788000 +0000">]>
Users by_roles within single role:
3.0.0 :002 > User.by_roles(['user'])
User Load (0.5ms) SELECT "users".* FROM "users" WHERE (roles #> '{user}') /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, account_uuid: "0812df2d-58ed-4231-aca5-ec7708a156bb", email: "admin#example.com", password_digest: [FILTERED], first_name: "Admin", last_name: "Admin", remember_token: nil, remember_token_expires_at: nil, roles: ["user", "admin"], created_at: "2021-12-02 11:51:50.684788000 +0000", updated_at: "2021-12-02 11:51:50.684788000 +0000">, #<User id: 2, account_uuid: "7a09830d-bfde-45eb-abeb-4b305a7bb374", email: "user_1#example.com", password_digest: [FILTERED], first_name: "User", last_name: "Adviseman", remember_token: nil, remember_token_expires_at: nil, roles: ["user"], created_at: "2021-12-02 17:40:12.172547000 +0000", updated_at: "2021-12-02 17:40:12.172547000 +0000">, #<User id: 3, account_uuid: "a0044954-6ad0-4d8f-9681-bd5dfcfa72b7", email: "user_2#example.com", password_digest: [FILTERED], first_name: "User", last_name: "Adviseman", remember_token: nil, remember_token_expires_at: nil, roles: ["user"], created_at: "2021-12-02 17:40:12.583594000 +0000", updated_at: "2021-12-02 17:40:12.583594000 +0000">, #<User id: 4, account_uuid: "7d26e5d5-beaf-48bd-ad98-f53044a7182b", email: "user_3#example.com", password_digest: [FILTERED], first_name: "User", last_name: "Adviseman", remember_token: nil, remember_token_expires_at: nil, roles: ["user"], created_at: "2021-12-02 17:40:12.847412000 +0000", updated_at: "2021-12-02 17:40:12.847412000 +0000">]>
Users by_roles within multiple roles:
3.0.0 :003 > User.by_roles(['user', 'admin'])
User Load (0.6ms) SELECT "users".* FROM "users" WHERE (roles #> '{user, admin}') /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, account_uuid: "0812df2d-58ed-4231-aca5-ec7708a156bb", email: "admin#example.com", password_digest: [FILTERED], first_name: "Admin", last_name: "Bezugliy", remember_token: nil, remember_token_expires_at: nil, roles: ["user", "admin"], created_at: "2021-12-02 11:51:50.684788000 +0000", updated_at: "2021-12-02 11:51:50.684788000 +0000">]>

What is inside my ruby array?

So I have an Array filled of what exactly?
myArray = [ #<Follower id: 1, username: "Prep Bootstrap", imageurl: "http://pbs.twimg.com//profile_images/2825468445/2a4...", user_id: "thefonso", follower_id: "2397558816", created_at: "2014-05-21 15:29:03", updated_at: "2014-05-21 15:29:03">, #<Follower id: 2, username: "JAVA Developer", imageurl: "http://pbs.twimg.com//profile_images/2825468445/2a4...", user_id: "thefonso", follower_id: "2352382640", created_at: "2014-05-21 15:29:05", updated_at: "2014-05-21 15:29:05">,
Follower id: 3, username: "JAVA Developer two", imageurl: "http://pbs.twimg.com//profile_images/2825468445/2a4...", user_id: "thefonso", follower_id: "2352382641", created_at: "2014-05-21 17:29:05", updated_at: "2014-05-21 17:29:05"> ]
Now I have many more of these inside this array with consecutive ids, etc..I'm confused by the #< >, is this an array of hashes? What am I looking at exactly? What is this an array of?
It looks like ActiveRecord's Followers class instances. Plus, it looks like you named your model improperly (with Rails practices, it should be named Follower).
Get the class of one of the objects and you'll know it
puts myArray[0].class

Split array. Ruby

Could you help me please with some problem?
I have array from database like this
str = Hiring::Tag.all
Hiring::Tag Load (0.1ms) SELECT `hiring_tags`.* FROM `hiring_tags`
=> [#<Hiring::Tag id: 1, name: "tag1", created_at: "2013-12-10 11:44:39", updated_at: "2013-12-10 11:44:39">,
#<Hiring::Tag id: 2, name: "tag2", created_at: nil, updated_at: nil>,
#<Hiring::Tag id: 3, name: "tag3", created_at: nil, updated_at: nil>,
#<Hiring::Tag id: 4, name: "wtf", created_at: "2013-12-11 07:53:04", updated_at: "2013-12-11 07:53:04">,
#<Hiring::Tag id: 5, name: "new_tag", created_at: "2013-12-11 10:35:48", updated_at: "2013-12-11 10:35:48">]
And I need to split this array like this:
data:[{id:1,name:'tag1'},{id:2,name:'tag2'},
{id:3,name:'tag3'},{id:4,name:'wtf'},{id:5,name:'new_tag'}]
Help me please!
if you use ActiveRecord 4.0
Hiring::Tag.pluck(:id, :name).map{ |id, name| {id: id, name: name} }
One possible solution:
Hiring::Tag.all.map {|h| {id: h.id, name: h.name} }
See the documentation for map.
You can try below code.
Hiring::Tag.all.inject({}) { |h, f| h[f.name.to_sym] = f.value; h }
OR
Hiring::Tag.all.map { |f| [f.name.to_sym, f.value] }]

Rails Has Many relation

I have two models that two relationships between them
class Tracking
include Mongoid::Document
belongs_to :origin_courier, :class_name => "Courier", foreign_key: "origin_courier_id"
belongs_to :destination_courier, :class_name => "Courier", foreign_key: "destination_courier_id"
end
class Courier
include Mongoid::Document
has_many :origins, class_name: 'Tracking', foreign_key: "origin_courier_id"
has_many :destinations, class_name: 'Tracking', foreign_key: "destination_courier_id"
end
When I assign a courier to the origin_courier of a newly created tracking, it run fine.
1.9.3p194 :015 > t = Tracking.new
=> #<Tracking _id: 4fbcc2772cfb397930000003, _type: nil, created_at: nil, updated_at: nil, origin_courier_id: nil, destination_courier_id: nil>
1.9.3p194 :016 > t.origin_courier = Courier.last
=> #<Courier _id: 4fbcbb072cfb397657000004, _type: nil, created_at: 2012-05-23 10:25:11 UTC, updated_at: 2012-05-23 10:25:11 UTC>
1.9.3p194 :017 > t
=> #<Tracking _id: 4fbcc2772cfb397930000003, _type: nil, created_at: nil, updated_at: nil, origin_courier_id: BSON::ObjectId('4fbcbb072cfb397657000004'), destination_courier_id: nil>
1.9.3p194 :018 > t.save
=> true
1.9.3p194 :019 > t
=> #<Tracking _id: 4fbcc2772cfb397930000003, _type: nil, created_at: 2012-05-23 10:57:14 UTC, updated_at: 2012-05-23 10:57:14 UTC, origin_courier_id: BSON::ObjectId('4fbcbb072cfb397657000004'), destination_courier_id: nil>
But when I assign a courier to the destination_courier of a newly created tracking, it duplicates the value to origin_courier
1.9.3p194 :020 > t2 = Tracking.new
=> #<Tracking _id: 4fbcc3002cfb397930000004, _type: nil, created_at: nil, updated_at: nil, origin_courier_id: nil, destination_courier_id: nil>
1.9.3p194 :021 > t2.destination_courier = Courier.last
=> #<Courier _id: 4fbcbb072cfb397657000004, _type: nil, created_at: 2012-05-23 10:25:11 UTC, updated_at: 2012-05-23 10:25:11 UTC>
1.9.3p194 :022 > t2.save
=> true
1.9.3p194 :023 > t2
=> #<Tracking _id: 4fbcc3002cfb397930000004, _type: nil, created_at: 2012-05-23 11:00:39 UTC, updated_at: 2012-05-23 11:00:39 UTC, origin_courier_id: BSON::ObjectId('4fbcbb072cfb397657000004'), destination_courier_id: BSON::ObjectId('4fbcbb072cfb397657000004')>
How can I resolve this?
Thanks.
(You mixed new Hash notaion (1.9.3) with older one in Tracking)
Did you try inverse_of instead of foreign_key ?
class Tracking
include Mongoid::Document
belongs_to :origin_courier, class_name: "Courier", inverse_of: :origins
belongs_to :destination_courier, class_name: "Courier", inverse_of: :destinations
end
and
class Courier
include Mongoid::Document
has_many :origins, class_name: 'Tracking', inverse_of: :origin_courier
has_many :destinations, class_name: 'Tracking', inverse_of: :destination_courier
end
https://github.com/mongoid/mongoid/issues/2038
It is bug of Mongoid.
Durran has fixed it.
Echo "very strange,"
The following modification also works, and I present it only because it might shed some light on the underlying problem.
class Courier
include Mongoid::Document
has_many :origin_trackings, class_name: "Tracking", foreign_key: :origin_tracking_id
has_many :destination_trackings, class_name: "Tracking", foreign_key: :destination_tracking_id
end
But I recommend NOT using foreign_key and DO second the recommendation to use inverse_of by Maxime Garcia.
For has_many/belongs_to, the relationship only has to be tracked on one side, even if the relationship is defined on both sides,
So like Active Record, Mongoid chooses for you, in this case to efficiently put the single link into the Tracking instance,
rather than growing an array of links in the Courier instance.
But a possible collision on foreign_key origin_courier_id for Tracking and Courier (or on foreign_key destination_courier_id for Tracking and Courier)
should not result in confusion between origin_* and destination_*.
I've looked at the metadata, which is only available for links that are set, and the metadata looks OK.
It's certainly a strange problem that would be interesting to investigate further as time and priorities permit.
Anyone else have some insight or knowledge of Mongoid internals?

Resources