Rails new_all in controller? - ruby-on-rails

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' }])

Related

Rails update_nested_attributes. HOw do update if exists, create if it does not?

Say I have two tables, trees and apples and a joined table tree_apples. Say the tree_apples table has a couple of important columns called rotten (boolean) and branch (int).
Say in the controller for trees, I have this:
#tree.update_nested_attributes(tree_params) and my tree_params method look like this:
tree_apple_params: {
:apple_id,
:rotten,
:branch
}
Say the tree that I'm updating already has a tree_apple with an id of 3 that is rotten: true and branches: nil and the incoming params into this controller to update the branch has params that look like this:
tree_apple_params: [{
apple_id: 3,
rotten: nil,
branch: 5
},
{
apple_id: 4,
rotten: nil,
branch: 6
},
...
]
So it's params to create or update a bunch of tree_apples. The page that the params came from wants to update the branch for tree_apple that references the apple_id of 3, and for this tree_apple it doesn't provide any input about the rotten state. I do NOT want to create another tree_apple that references apple_id: 3 that has nil for the rotten_state. I want to update the existing tree_apple. So, for this tree_apple, I'd like to find it, and then update it with branch 5. But for all the other params that reference apples that do not exist on this tree, I'd like to create new tree_apples if the tree_apple doesn't exist.
Is there a way to do this? Does this logic belong in the controller or in the model as a callback of some kind?
Look into find_or_create_by
Something along the lines of:
tree_params.each do |params|
tree_apple = TreeApple.find_or_create_by(apple_id: params[:apple_id])
tree_apple.update_attributes(branch: params[:branch], rotten: params[:rotten])
end
in your controller.
You have to pass the id of the tree_apple record if you want to update it e.g.
tree_apple_params: [{
id: 1, #passing the id of the tree_apple record here will update existing records
apple_id: 3,
rotten: nil,
branch: 5
},
{ #passing NO id here will create records
apple_id: 4,
rotten: nil,
branch: 6
},
...
]
And obviously allow the id in your params:
tree_apple_params: {
:id,
:apple_id,
:rotten,
:branch
}

FactoryGirl rspec, while creating multiple factories at once

When I am creating multiple object of Factory using method create_list, the order and where method don't work on it because create_list creates the array of factory objects.
users = FactoryGirl.create_list(:user, 5)
users.order('name ASC')
It gives undefined method order for Array
So, what should I do to create the multiple factory objects inside the ActiveRecord Collection?
The order and where methods are not defined on Array but on ActiveRecord::Relation. It's the kind of thing that gets passed around by the ActiveRecord query interface. You simply cannot run a query on an array. To run a query you need to start from scratch:
create_list, :user, 5
users = User.where(...).order(name: :asc)
But you might as well directly pass your arguments to create_list so that the condition is satisfied without needing to re-select the users. I also often find myself writing arrays explicitly when I need to alter values in each row e. g.
users = [
create(:user, name: 'Alfred'),
create(:user, name: 'Bob'),
create(:user, name: 'Charlie'),
create(:user, name: 'David'),
create(:user, name: 'Egon')
]
The users are already ordered by name and you're good to go. If you have some condition in the where clause that for example separates the users in two groups, you can just go ahead and separate these users directly. For example imagine we have an admin flag in the users table and you want to create many users, some being admins and some not. Then you'd do
admins = [
create(:user, name: 'Alfred', admin: true),
create(:user, name: 'Charlie', admin: true),
create(:user, name: 'Egon', admin: true)
]
visitors = [
create(:user, name: 'Bob'),
create(:user, name: 'David')
]
No need to query at all. Of course you can also do that in let syntax if you like.

MongoId rails3, get inner array elements

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"]

Intersection of 2 arrays of hashes by hash value (such as id)

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

Is there any way that ruby's `create!` can make multiple objects at once?

I have a system that occasionally spits out 2 objects. Is there any magic to create! that would allow it to create two objects? E.G. if I say
self.class.create! make_up_attributes
and make_up_attributes passes a 2 item hash, can this create 2 objects of type self?
(note, create is probably an ActiveRecord method, in Rails)
Yep, simply pass in an Array of attribute hashes, like so:
self.class.create!([{:name => "John", :age => 26},
{:name => "Fred", :age => 50}])
See the docs

Resources