Rails: Use a variable as a hash key - ruby-on-rails

I've been trying to do this for the past 10 hours, but it's been useless.
For example:
Event.where(login_screen: Time.now-8.days ..Time.now)
I have an Event table and login_screen is one of the column names. I'm listing them in a drop-down menu and I'd like to take the event names as a variable. It's in the request params like this: params[:segmentation][:first_event]. When I tried to give it like:
Event.where(params[:segmentation][:first_event] Time.now-8.days ..Time.now)
...it didn't work. I tried to use to_sym but that didn't help either.
How can I use a variable as a symbol?
Another question:
What's the difference between :hello and hello: ?

It's alternative syntax for ruby hashes with symbols as keys
Event.where(login_screen: Time.now-8.days ..Time.now)
is the same as
Event.where(:login_screen => Time.now-8.days ..Time.now)
So, if you store key in variable you need use 'hash rocket' syntax:
Event.where(params[:segmentation][:first_event] => Time.now-8.days ..Time.now)

these are the different ways to pass arguments in where clause:--
User.where(["name = ? and email = ?", "Joe", "joe#example.com"])
User.where(["name = :name and email = :email", { name: "Joe", email: "joe#example.com" }])
User.where("name = :name and email = :email", { name: "Joe", email: "joe#example.com" })
using hash:-
User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })
User.where({ name: ["Alice", "Bob"]})
User.where({ name: "Joe", email: "joe#example.com" })

Related

Conditionally include attribute is create method - Rails 5

What would be the best way of conditionally including an attribute in a create (or any method(attr, attr, attr) style method)?
#user = User.find_by_name("Sam") # <- might not exist
Store.create(
name: "Some Store",
email: "store#example.com",
user_id: #user.id if #user.present? # <- CONCEPT ONLY - Should be added if condition is true to prevent error
)
the line user_id: #user.id throws an error if #user wasn't found and is therefore nil.
You forgot that .create()'s argument is a shortcut for a hash. Make the hash explicit:
hash = {
name: "Some Store",
email: "store#example.com"
}
hash[:user_id] = #user.id if #user.present?
Store.create(hash)
Another option is to pass .create a block:
Store.create do |s|
s.name = "Some Store"
s.email = "store#example.com"
s.user_id = #user.id if #user
end
The most minimal change I could make for your code to work is:
Store.create(
name: "Some Store",
email: "store#example.com",
user_id: #user&.id
)
This is using the safe navigation operator (&.) to "ignore method calls" on nil values.
However, why are you fetching a possibly-nil object and then trying to call a method on it? Given the context of your original post, you could instead just do:
Store.create(
name: "Some Store",
email: "store#example.com",
user: #user
)
This will work fine, regardless of whether or not the #user exists.
...Or perhaps even, what you really intend to do is something like:
Store.create(
name: "Some Store",
email: "store#example.com",
user: User.find_or_create_by(name: 'Sam')
)

Rails Faker - How to generate a custom domain email?

Ideally I want to create a fake email based on the Faker generated email, but I want to achieve something like: faker_first_name#mydomain.com. The documentation shows you can do it for the first part but not the actual domain. Is there a way to achieve this?
20.times do
u = User.new(first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
email: Faker::Name.first_name"#THISPART.com",
)
u.save
end
Update Dec 2019:
Faker version v2.8.0 introduced the domain support - Release v2.8.0
Now, It is possible to pass the domain while creating the email address.
Following are the possible options:
Faker::Internet.email #=> "eliza#mann.net"
Faker::Internet.email(name: 'Nancy') #=> "nancy#terry.biz"
Faker::Internet.email(name: 'Janelle Santiago', separators: '+') #=> janelle+santiago#becker.com"
Faker::Internet.email(domain: 'example.com') #=> alice#example.com"
Note: Above code sample is from the faker documentation
Old Answer:
Well there is no such provision to pass domain name to the method
But, you can make use of Faker::Internet.user_name
User.new(
first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
email: "#{Faker::Internet.user_name}#customdomain.com"
)
I think you just missed the string concat: +
:006 > Faker::Name.first_name+"#THISPART.com"
=> "Irving#THISPART.com"
And if you meant keeping the same name, save it before:
fn = Faker::Name.first_name
sn = Faker::Name.last_name
u = User.create(
:forename => fn,
:surname => sn,
:email => "#{fn}.#{sn}#yourdomain.net",
Faker::Name.first_name will always generate a new random value.
Recent versions of Faker has a built in support for custom email subdomains.
Faker::Internet.email(domain: 'customdomain.com')

Merge ActionController::Parameters with rails 5

In rails 4, I can merge! StrongParams, but since rails 5 (beta1) merge! is not available. Which is the best way to do that in a controller
params = ActionController::Parameters.new({
name: 'Francesco',
age: 22,
role: 'admin'
})
params.merge!(city: "Los Angeles")
As far as I can see from the source code, you have merge not merge!. In other words, it doesn't seem to be possible to modify the hash in place.
The following code will work:
params = ActionController::Parameters.new({
name: 'Francesco',
age: 22,
role: 'admin'
})
params = params.merge(city: "Los Angeles")
params.merge!(city: "Los Angeles") works with Rails5.0.1
In Rails 5: ActionController::Parameters Now Returns an Object Instead of a Hash.
so you must use params.permit(:city).to_h to access city.
For more details how ActionController::Parameters works in Rails5?
Ref: http://www.rortuts.com/ruby-on-rails/rails5-actioncontrollerparameters/
Hope this helps to anyone.
def comment_params
params.require(:comment).permit(:title, :user_id, :color)
end
I want to merge color attribute with my custom color code or name. so to merge color attribute dynamically
Ininitialize params in rails 5 like this,
params = ActionController::Parameters.new(comment_params)
params = params.merge(color: "green")
new_params = params.to_h.merge(city: "Los Angeles")

Update a table in rails

I have a table A(:name, :address, :phone) and want to update the names and addresses of all the records. The following lines of code helps me doing it but takes a lot of time :
A.find_each(batch_size: 10000) do |a|
new_name = "xyz"
new_address = "abc"
A.find(a.id).update(name: name, address: new_address)
end
It takes times because of the last line as I am finding the record first, then updating it. Now when I do this :
A.find_each(batch_size: 10000) do |a|
a.name = "xyz"
a.address = "abc"
a.save
end
The names and addresses don't get updated in this case but a.save returns true. What could be wrong?
Can you try printing out the errors while saving if any:
A.find_each(batch_size: 10000) do |a|
a.name = "xyz"
a.address = "abc"
a.save
puts a.errors.full_messages
end
Try to do this like:
A.find_each(batch_size: 10000){ |a| a.update_attributes(name: 'name', address: 'address', phone: 23213) }
If you want all records to be updated with same value, the below solution will be fast.
A.update_all(name: 'xyz', address: 'abc')
You can fire direct SQL query and update directly using single SQL statement
A.find_by_sql "UPDATE table SET name = 'abc' and address = 'xyz'";
A.update_all(name: 'xyz', address: 'abc')

Mongoid: Creating many objects with a single call

I have 1000 users that i will be retrieving from Twitter, and I would like to save them at one shot, as opposed to doing 1000 insertions individually.
How can I do this on Mongoid? Something like this would rock:
TwitterUser.createMany([{:name=>u1}, {:name=>u2},{:name=>u3}] )
You should use the Mongo ruby driver to do this. You can pass an array of hashes to the insert method to create multiple documents at once (more info on this google groups discussion). Mongoid makes it easy to access the ruby driver.
The code would look something like this:
user_list = twitter_accounts.map do |account|
# create a hash of all the fields to be stored in each document
{ 'name' => account.name,
'username' => account.username
# some other fields...
}
end
Mongoid.master['twitter_users'].insert(user_list)
You almost got it, it's create, not createMany. You can use it like this:
TwitterUser.create([
{ username: "u1", display_name: "Display Name 1" },
{ username: "u2", display_name: "Display Name 2" },
{ username: "u3", display_name: "Display Name 3" }
])
Also, as #bowsersenior points out, it's a good idea to use it with Array#Map:
TwitterUser.create(
#users_array.map do |u|
{ username: u.username, display_name: u.name }
end
)
From the Mongoid#Persistence Docs:
Model.create
Insert a document or multiple documents into the database
Model.create!
Insert a document or multiple documents into the database, raising an error if a validation error occurs.
Just use MongoidModel.create directly.

Resources