Wildcard for nested params - ruby-on-rails

Is there a way I can test for both these params to be true? Some sort of wildcard value for the first key?
params[:book][:return_to]
params[:work][:return_to]
At the moment I'm having to do:
if params[:book] and params[:book][:return_to]
# blah
elsif params[:work] and params[:work][:return_to]
# blah

Hashie is the solution I've used.
https://github.com/intridea/hashie
From their readme:
user = {
name: { first: 'Bob', last: 'Boberts' },
groups: [
{ name: 'Rubyists' },
{ name: 'Open source enthusiasts' }
]
}
user.extend Hashie::Extensions::DeepFind
user.deep_find(:name) #=> { first: 'Bob', last: 'Boberts' }

Related

Create a deep nested hash using loops in Ruby

I want to create a nested hash using four values type, name, year, value. ie, key of the first hash will be type, value will be another hash with key name, then value of that one will be another hash with key year and value as value.
The array of objects I'm iterating looks like this:
elements = [
{
year: '2018',
items: [
{
name: 'name1',
value: 'value1',
type: 'type1',
},
{
name: 'name2',
value: 'value2',
type: 'type2',
},
]
},
{
year: '2019',
items: [
{
name: 'name3',
value: 'value3',
type: 'type2',
},
{
name: 'name4',
value: 'value4',
type: 'type1',
},
]
}
]
And I'm getting all values together using two loops like this:
elements.each do |element|
year = element.year
element.items.each |item|
name = item.name
value = item.value
type = item.type
# TODO: create nested hash
end
end
Expected output is like this:
{
"type1" => {
"name1" => {
"2018" => "value1"
},
"name4" => {
"2019" => "value4"
}
},
"type2" => {
"name2" => {
"2018" => "value2"
},
"name3" => {
"2019" => "value3"
}
}
}
I tried out some methods but it doesn't seems to work out as expected. How can I do this?
elements.each_with_object({}) { |g,h| g[:items].each { |f|
h.update(f[:type]=>{ f[:name]=>{ g[:year]=>f[:value] } }) { |_,o,n| o.merge(n) } } }
#=> {"type1"=>{"name1"=>{"2018"=>"value1"}, "name4"=>{"2019"=>"value4"}},
# "type2"=>{"name2"=>{"2018"=>"value2"}, "name3"=>{"2019"=>"value3"}}}
This uses the form of Hash#update (aka merge!) that employs a block (here { |_,o,n| o.merge(n) } to determine the values of keys that are present in both hashes being merged. See the doc for definitions of the three block variables (here _, o and n). Note that in performing o.merge(n) o and n will have no common keys, so a block is not needed for that operation.
Assuming you want to preserve the references (unlike in your desired output,) here you go:
elements = [
{
year: '2018',
items: [
{name: 'name1', value: 'value1', type: 'type1'},
{name: 'name2', value: 'value2', type: 'type2'}
]
},
{
year: '2019',
items: [
{name: 'name3', value: 'value3', type: 'type2'},
{name: 'name4', value: 'value4', type: 'type1'}
]
}
]
Just iterate over everything and reduce into the hash. On the structures of known shape is’s a trivial task:
elements.each_with_object(
Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } # for deep bury
) do |h, acc|
h[:items].each do |item|
acc[item[:type]][item[:name]][h[:year]] = item[:value]
end
end
#⇒ {"type1"=>{"name1"=>{"2018"=>"value1"},
# "name4"=>{"2019"=>"value4"}},
# "type2"=>{"name2"=>{"2018"=>"value2"},
# "name3"=>{"2019"=>"value3"}}}

ActiveRecord: Skip validation when saving multiple objects

I know I can skip validations for an individual save, like this:
User.new(name: 'John').save(validate: false)
But how can I do that when saving multiple objects at once? Like this:
Category.create([
{ name: 'Apps' },
{ name: 'Songs' },
{ name: 'Movies' }
])
I found this gem: https://github.com/zdennis/activerecord-import
It works like this:
categories = [
Category.new(name: 'Apps'),
Category.new(name: 'Songs'),
Category.new(name: 'Movies')
]
Category.import(categories, validate: false)
It is also possible to use plain arrays instead of ActiveRecord objects.
I guess it generates pure SQL when validate is set to false so it can skip validations.
You can't do that with create. If you really must skip validations you can do something like this:
[
{ name: 'Apps' },
{ name: 'Songs' },
{ name: 'Movies' }
].each do |attributes|
c = Category.new(attributes)
s.save(validate: false)
end

Seeding in Ruby on Rails

I have several deeply nested models and I would like to seed my database. The models are as following: Each restaurant has many menus. Each menu has many categories. Each category has many meals. Currently, my seed looks like this:
restaurant_seed = [
{
name: "KFC",
address: "Sofia",
description: "Fast food.",
phone_number: "88888888"
}
]
menu_seed = [
{
name: 'Spring menu.',
active: true
},
}
name: 'Winter menu.',
active: false
}
]
category_seed = [
{
name: "Dessert",
available_all_day: false,
age_restriction: false,
category_avatar: File.open(File.join(Rails.root, "app/assets/images/desserts.jpg"))
},
{
name: "Salad",
available_all_day: true,
age_restriction: false,
category_avatar: File.open(File.join(Rails.root, "app/assets/images/salads.jpeg"))
}
]
meal_seed = [
{
name: "Shopska salata",
meal_avatar: File.open(File.join(Rails.root, "app/assets/images/shopska_salad.jpg"))
},
{
name: "Shisha",
meal_avatar: File.open(File.join(Rails.root, "app/assets/images/shisha.jpg"))
}
]
However, I do not know how to actually seed the database with that info. The idea is that each restaurant will have all of the menu seeds, each of the menus in each restaurant will have each category from the category seed and so on. Thank you for any suggestions!
Write a method to iterate all seeds and create corresponding records.
def setup_restaurants(restaurant_seed, menu_seed, category_seed, meal_seed)
restaurant_seed.each do |r_seed|
restaurant = Restaurant.create(r_seed)
menu_seed.each do |m_seed|
menu = restaurant.menus.create(m_seed)
category_seed.each do |c_seed|
category = menu.categories.create(c_seed)
meal_seed.each do |mm_seed|
category.meals.create(mm_seed)
end
end
end
end
end

Migrating from Mandrill to SparkPost -- Rails API

I am migrating from Mandrill to SparkPost and have a Rails back-end.
The data structure I currently have is the following --
message = {
subject: "Welcome",
merge_vars: [{
rcpt: user.email,
vars: email_vars(user)
}],
to:[{
email: user.email,
name: user.name
}],
track_clicks: true,
track_opens: true,
inline_css: true,
}
This sends the response --
m = Mandrill::API.new
template_content = []
result = m.messages.send_template 'email-confirmation', template_content, message
Would I need to update the JSON data structure at all?
Once JSON is good, how do I pass values to specific template with SparkPost?
I attempted the following --
m = SparkPost::Client.new()
template_content = []
result = m.messages.send_template 'email-confirmation', template_content, message
But I have also seen this --
host = 'https://api.sparkpost.com'
SparkPost::Request.request("#{host}/api/v1/transmissions", API_KEY, {
recipients: [
{
address: { email: user.email },
substitution_data: {
first_name: user.name,
email: user.email
}
}
],
content: {
template_id: 'email-confirmation'
},
substitution_data: {
name: user.name,
email: user.email
}
})
Appreciate the help!
If you're using the official gem, it has a convenient method called send_payload which you can use to send a prepared payload.
The substitution_data inside recipients collection is a per recipient substitution.
For example, I've following templates.
To send using this template, this is my complete code
sp = SparkPost::Client.new() # pass api key or get api key from ENV
payload = {
recipients: [
{
address: { email: 'RECIPIENT1' },
substitution_data: {
name: 'User one',
username: 'userone'
}
}, {
address: { email: 'RECIPIENT2' },
substitution_data: {
name: 'User two',
username: 'user2'
}
}
],
content: {
template_id: 'test-template'
},
substitution_data: {
company: 'Awesome company'
}
}
response = sp.transmission.send_payload(payload)
p response
The email will look like
Hello User one, Your username, userone, is created. Thanks Awesome company

Wrap parameters in AngularJS service for update API request

I'm trying to do update with AngularJS and API
Service: expense.js
angular
.module('timeTrackerApp.services',[])
.service('Expense', ['$resource', function ($resource) {
return $resource('/api/v1/expenses/:id', {id:'#id'}, {
'update': {
method: 'PUT'
},
'destroy': {
method: 'DELETE'
}
})
}])
Controller: expenses_controller.rb
def permitted_params
params.require(:expense).permit(:name, :price)
end
So expected JSON format is { expense: { name: "value", price: value } }
but i'm getting { name: "value", price: value }
So can anyone help me wrap this into root node ( expense ) ?
Rails automatically does wrap parameters when controller name matches a model name. Check doc.
If ever it fails, you can do it manually, in your controller:
wrap_parameters :expense, include: [:name, :price]
so if you receive:
{ name: 'name', price: 'price' }
Controller will give you:
{ name: 'name', price: 'price', expense: { name: 'name', price: 'price' } }
So do this server side since its neat and simple.

Resources