I have 2 Models, Kid and friend_list. To the the kid I use:
k = Kid.where(email: "adfadf#adfadsfa.com").first
Then, to get the friend list I type:
k.friend_list
and I get:
[#<FriendList _id: 5305cb6485216d2689004785, _type: nil, name: "Friends", members: ["5374a1f320db90054c0000ea", "537c63ea20db9040d2000332"], kid_id: BSON::ObjectId('5305cb6285216d2689004742'), teacher_id: nil>]
But I only need the "members".
I tried
k.friend_list.members, but I get
NoMethodError: undefined method `members' for
#<Array:0x007fcf4b013138> from /Users/jeanosorio/.rvm/gems/ruby-1.9.3-p484#blabloo/gems/mongoid-2.8.1/lib/mongoid/criteria.rb:387:in
`method_missing'
How can I get only the members array??
Thanks in advance.
It seems that friend_list returns an Array of FriendList.
You can create a new list composed of the values of the members getter using map:
k.friend_list.map(&:members)
# => [["5374a1f320db90054c0000ea", "537c63ea20db9040d2000332"]]
Or, alternatively, if you only meant to have a single FriendList per Kid, you should change your model to a single FriendList object.
For the current model, you can also do:
k.friend_list.first.members
# => ["5374a1f320db90054c0000ea", "537c63ea20db9040d2000332"]
Related
I have used code in a controller to update all records for a different model using an array of ids:
Expense.update_all({reimbursed: true}, {id: params[:expense_ids]})
Is there a way to new/build/create records?
Something like:
Expense.new_all({reimbursed: true}, {expense_id: params[:expense_ids]})
Thanks for your help!
You can pass multiple attribute hashes to create to create multiple instances of the model. From the docs:
# Create an Array of new objects
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
In my rails app, I have a user model and a linkedin_connection model. Linkedin_connection belongs to user and user has_many linkedin_connections.
What's the best way to create a crossover array of connections between user1 and user2?
============== EDIT ============== EDIT ============== EDIT ==============
I realized that this is sort of a different problem than I originally thought. I have 2 arrays of hashes. Each hash has an id element. How can I find the intersection of two hashes by their ids?
Example
user1.linkedin_connections => [{id: "123xyz", name: "John Doe"}, {id: "789abc", name: "Alexander Supertramp"}]
user2.linkedin_connections => [{id: "456ijk", name: "Darth Vader"}, {id: "123xyz", name: "John Doe"}]
cross_connections => [{id: "123xyz", name: "John Doe"}]
How can I calculate "cross_connections?"
Thanks!
What you want is the intersection of the two arrays. In ruby, that's easy, using the & operator:
crossover_connections = user1.linkedin_connections.to_a & user2.linkedin_connections.to_a
I am able to get products from an order, but I still didn't find a way to get its option_values in order to produce it. This is how I found the product:
p = Order.find_by_number("R326153622").products.first
Then, I have its option_types through p.option_types which gives me:
=> [#<OptionType id: 935339118, name: "gender", ...>,
#<OptionType id: 935339117, name: "size", ...>,
#<OptionType id: 643188970, name: "color", ...>]
Ok! Now my headache starts. I just can't realize where to find the gender, size, and color of this product, chosen by the customer when he put it in his cart.
I'm giving up and calling the customer right away, but still wanted to understand it =D
you can do it like so
p = Order.find_by_number("R326153622").products.first
then
p.option_types.map(&:name)
what is happening here is that this form
array.map(&:method_name)
call this methods on each one of array members
How do you get the id of a rails model before it is saved?
For example, if I create a new model instance, how can I get its ID before it is saved?
I know that the id is created onsave and according to the database but is there a workaround?
I was looking for this too, and I found an answer:
Let's suppose model name is "Model" and table name is "models"
model.rb
before_save {
next_id=Model.connection.select_value("Select nextval('models_id_seq')")
}
This will output the value your record will take for id IF it gets saved
Usually when people think they need to do this they actually do not need to do it. Like John says, explain what you are trying to do and someone can probably suggest a way to do it without having to know the id in advance.
This is less a Rails question and more a database question. This is a problem that will present itself in any web application framework, and the solution is the same in all places. You have to use a database transaction.
The basic flow will work like this.
Open a transaction
Save your model
Use the ID assigned by the database
If it turns out you actually don't want to keep this model in the database, roll back the transaction.
If it turns out you want to keep the model in the database, commit the transaction.
The main thing you will notice from this approach is that there will be gaps in your IDs where you rolled back the transaction.
Using the default Rails convention of an auto-incrementing integer primary key, there's no way to get the ID of a model before it's saved because it's generated by the RDBMS when the new row is inserted in the relevant table.
What problem are you actually trying to solve?
Most of the time when I needed an id can be grouped into a short list.
When creating nested associations or connectin of the associations through.
Let's assume we have: :user that have :pets through :user_pets association, where we will save their type.
If we have a properly configured "has_many: through Association" we can just
User.pets.create(name: "Rex") but this is too simplistic, as we want to creat :pet type in :user_pets.
u = User.create(name: "Cesar")
u.id # => 1 # works fine
p = u.pets.create(name: 'Rex')
# => rails will create UserPets => {id: 1, user_id: 1, pet_id: 1} for us
# But now we have a problem, how do we find :user_pets of our :pet?
# remember we still need to update the :type, the ugly (wrong) way:
up = p.user_pets.first
up.type = 'dog'
up.save! # working but wrong
# Do you see the problems here? We could use an id
P = Pet.new( name: "Destroyer" )
p.id # will not work, as the pet not saved yet to receive an id
up = UserPet.new( user_id: U.id, pet_id: p.id )
# => UserPet {id: 2, user_id: 1, pet_id: nil} # as we expected there is no id.
# What solutions do we have? Use nested creation!
# Good
up = UserPet.new(user_id: u.id, type: "dog")
# even better
up = u.user_pets.new(type: "dog")
# it's just a shortcut for the code above,
# it will add :user_id for us, so let's just remember it.
# Now lets add another 'new' from our creatd 'user_pet'
p = up.pets.new(name: "Millan")
user.save!
# => UserPet: {id: 3, user_id: 1, pet_id: 2, type: 'dog'} # => Pet: {id: 2, name: "Sam"}
# everything is working! YEY!
# we can even better, than writing in the beginning "User.create",
# we can write "User.new" and save it with all the nested elements.
You saw how this created all the ids for us? Let's move to something even more complex!
Now we have an additional table :shampoo that exactly as :user_pet, belongs to a :pet and a :user
We need to create it without knowing the id of the :user and :pet
u = User.new('Mike')
up = u.user_pets.new(type: "cat")
p = up.pets.new(name: "Rowe")
# But what are we doing now?
# If we do:
s = u.shampoos.new(name: "Dirty Job")
# => Shampoo: {user_id: 2, pet_id: nil, name: "..."}
# We get "pet_id: nil", not what we want.
# Or if we do:
s = p.shampoos.new(name: "Schneewittchen")
# => Shampoo: {user_id: nil, pet_id: 3, name: "..."}
# We get "user_id: nil", in both cases we do not get what we want.
# So we need to get the id of not created record, again.
# For this we can just do as in the first example (order is not important)
s = u.shampoos.new(name: "Mission Impossible")
# => Shampoo: {id: 3, user_id: 2, pet_id: nil, name: "..."}
s.pet = p # this will give the missing id, to the shampoo on save.
# Finish with save of the object:
u.save! #=> Shampoo: {id: 3, user_id: 2, pet_id: 3, name: '...'} # => Pet: ...
# Done!
I tried to cover most common causes when you need element id, and how to overcome this. I hope it will be useful.
I don't believe there are any workarounds since the id is actually generated by the database itself. The id should not be available until after the object has been saved to the database.
Consider doing what you want right after the instance is created.
after_create do
print self.id
end
First understand the structure of database.
Id is generated using sequence
increment done by 1 (specified while creating sequence)
Last entry to database will have highest value of id
If you wanted to get id of record which is going to be saved,
Then you can use following:
1. id = Model.last.id + 1
model = Model.new(id: id)
model.save
# But if data can be delete from that dataabse this will not work correctly.
2. id = Model.connection.select_value("Select nextval('models_id_seq')")
model = Model.new(id: id)
model.save
# Here in this case if you did not specified 'id' while creating new object, record will saved with next id.
e.g.
id
=> 2234
model = Model.new(id: id)
model.save
# Record will be created using 'id' as 2234
model = Model.new()
model.save
# Record will be created using next value of 'id' as 2235
Hope this will help you.
I just ran into a similar situation when creating a data importer. I was creating a bunch of records of different types and associating them before saving. When saving, some of the records threw validation errors because they had validate_presence_of a record that was not yet saved.
If you are using postgres, active record increments the id it assigns to a Model by keeping a sequence named models_id_seq (sales_id_seq for Sale etc.) in the database. You can get the next id in this sequence and increment it with the following function.
def next_model_id
ActiveRecord::Base.connection.execute("SELECT NEXTVAL('models_id_seq')").first["nextval"].to_i
end
However, this solution is not good practice as there is no guarantee that active record will keep id sequences in this way in the future. I would only use this if it was used only once in my project, saved me a lot of work and was well documented in terms of why it should not be used frequently.
I know it's an old question, but might as well throw my answer in case anyone needs to reference it
UserModel
class User < ActiveRecord::Base
before_create :set_default_value
def set_default_value
self.value ||= "#{User.last.id+1}"
end
I would like to know if it is possible to get the types (as known by AR - eg in the migration script and database) programmatically (I know the data exists in there somewhere).
For example, I can deal with all the attribute names:
ar.attribute_names.each { |name| puts name }
.attributes just returns a mapping of the names to their current values (eg no type info if the field isn't set).
Some places I have seen it with the type information:
in script/console, type the name of an AR entity:
>> Driver
=> Driver(id: integer, name: string, created_at: datetime, updated_at: datetime)
So clearly it knows the types. Also, there is .column_for_attribute, which takes an attr name and returns a column object - which has the type buried in the underlying database column object, but it doesn't appear to be a clean way to get it.
I would also be interested in if there is a way that is friendly for the new "ActiveModel" that is coming (rails3) and is decoupled from database specifics (but perhaps type info will not be part of it, I can't seem to find out if it is).
Thanks.
In Rails 3, for your model "Driver", you want Driver.columns_hash.
Driver.columns_hash["name"].type #returns :string
If you want to iterate through them, you'd do something like this:
Driver.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
which will output the following:
id => integer
name => string
created_at => datetime
updated_at => datetime
In Rails 5, you can do this independently of the Database. That's important if you use the new Attributes API to define (additional) attributes.
Getting all attributes from a model class:
pry> User.attribute_names
=> ["id",
"firstname",
"lastname",
"created_at",
"updated_at",
"email",...
Getting the type:
pry> User.type_for_attribute('email')
=> #<ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString:0x007ffbab107698
#limit=255,
#precision=nil,
#scale=nil>
That's sometimes more information than needed. There's a convenience function that maps all these types down to a core set (:integer, :string etc.)
> User.type_for_attribute('email').type
=> :string
You can also get all that data in one call with attribute_types which returns a 'name': type hash.
You can access the types of the columns by doing this:
#script/console
Driver.columns.each {|c| puts c.type}
If you want to get a list of all column types in a particular Model, you could do:
Driver.columns.map(&:type) #gets them all
Driver.columns.map(&:type).uniq #gets the unique ones
In rails 5 this will give you a list of all field names along with their data type:
Model_Name.attribute_names.each do |k| puts "#{k} = #{Model_Name.type_for_attribute(k).type}" end
Rails 5+ (works with virtual attributes as well):
Model.attribute_types['some_attribute'].type
This snippet will give you all the attributes of a model with the associated database data types in a hash. Just replace Post with your Active Record Model.
Post.attribute_names.map {|n| [n.to_sym,Post.type_for_attribute(n).type]}.to_h
Will return a hash like this.
=> {:id=>:integer, :title=>:string, :body=>:text, :created_at=>:datetime, :updated_at=>:datetime, :topic_id=>:integer, :user_id=>:integer}
Assuming Foobar is your Active Record model. You can also do:
attributes = Foobar.attribute_names.each_with_object({}) do |attribute_name, hash|
hash[attribute_name.to_sym] = Foobar.type_for_attribute(attribute_name).type
end
Works on Rails 4 too
In Rails 4 You would use Model.column_types.