ActiveRecord: Skip validation when saving multiple objects - ruby-on-rails

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

Related

Ruby on Rail: How can I use _destroy as an attribute to destroy an object on save (NOT NESTED)?

I have an app that uses a lot of nested objects/attributes. The general paradigm is to set _destroy as an attribute for something that you want to destroy. This only works for nested attributes though, and not the main object.
So this works as expected because it's nested:
params = {
member: {
name: 'joe',
posts_attributes: [
{ title: 'A post' }
{ title: 'A post to delete', _destroy: true }
]
}
}
But what I'd like to be able to do is destroy the main object in the same way:
params = {
member: {
name: 'joe',
_destroy: true,
posts_attributes: [
{ title: 'A post' }
]
}
}
Is there a native way to do this or a gem? Or would I have to roll my own.
Also I recognize that since this isn't part of the framework there might be reasons this is a bad idea that I haven't considered. I'm open to hearing what those might be.

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

ActiveModel::ForbiddenAttributesError in Rails 4?

I am getting the following error when trying to update a Rails model via the ActiveModel update method:
ActiveModel::ForbiddenAttributesError
I am aware of the strong parameters requirement in Rails 4 per the link below, but how do I whitelist the params in my case - an array of hashes? I cannot make sense of the documentation.
http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
Here are the json params that I am trying to process:
{
id: 1,
month: 'April',
measurements: [
{ id: 1, name: 'PT', location_1: '1.1', location_2: '1.2' },
{ id: 1, name: 'OT', location_1: '1.1', location_2: '1.2' },
.
.
]
}
Controller action:
def update
#Trying to update all measurements associated with this parent object
#params.permit(measurements: [{ :name, :location_1, :location_2 } ])
#This attempt causes a syntax error
measurements = params[:measurements]
measurements.each do |measurement|
current_measurement = Measurement.find(measurement[:id])
new_measurement = measurement.except(:id)
current_measurement.update(new_measurement)
end
.
.
end
to whitelist an array of attributes you'd code it this way...
params.permit(measurements: [ :name, :location_1, :location_2 ])

How to pass a Hash to Grape API method?

I'm having problems with the Grape gem and the parameters validation.
The idea behind this is to create a complex entity using nested attributes through an API service.
I have a method to create a trip, trip have many destinations and i want to pass that destinations using a hash (using the accepts_nested_attributes_for helper).
I have this grape restriction over the parameter:
requires :destinations, type: Hash
And I'm trying to send something like this:
{ destinations => [
{ destination: { name => 'dest1'} },
{ destination: { name => 'dest2'} },
{ destination: { name => 'dest3'} }
]}
In order to build something like the structure below inside the method and get the trip created:
{ trip: {
name: 'Trip1', destinations_attributes: [
{ name: 'dest1' },
{ name: 'dest2' },
{ name: 'dest3' }
]
}}
I'm using POSTMAN chrome extension to call the API method.
Here's a screen capture:
If someone can help me i would be very grateful.
By the looks of what you are trying to send, you need to change the Grape restriction, because destinations is an Array, not a Hash:
requires :destinations, type: Array
You don't need the "destination" hash when sending the request:
{ destinations => [
{ name => 'dest1', other_attribute: 'value', etc... },
{ name => 'dest2', other_attribute: 'value', etc... },
{ name => 'dest3', other_attribute: 'value', etc... }
]}
This creates an Array of hashes.
In order to send this through POSTMAN, you'll need to modify that destinations param your sending and add multiple lines in POSTMAN. Something like:
destinations[][name] 'dest1'
destinations[][other_attribute] 'value1'
destinations[][name] 'dest2'
destinations[][other_attribute] 'value2'
destinations[][name] 'dest3'
destinations[][other_attribute] 'value3'
Hope this answers your questions. Let me know if this is what you were looking for.

Populate a Scaffold via Seed

I have an Item's Scaffold which has approximately 200+ Item's which are pre-fix.
So adding them manually is really painful.
Can i populate the Scaffold in my seed-file and then db:seed on production ?
I don't know the proper method but i think it's something like this:
items = Item.create([
{ name: 'css' },
{ name: 'css3' },
{ name: 'ruby' },
{ name: 'rails' },
{ name: 'python' },
{ name: 'html' }
])
I'm searching for a Solution that will seed my Item's Scaffold...
Try the following code by adding remaining items in array in db/seeds.rb file and run rake db:seed command. That generates expected records in items table.
['css','rubyonrails','java'].each do |item|
Item.find_or_create_by_name(:name => item)
end
Good luck.
You have to do it that way, but you don't need to asign it to the items variable.
You just have to add to the seed.rb file the code with your items. I've added the delete_all before to avoid creating duplicate items.
Item.delete_all
Item.create([
{ name: 'css' },
{ name: 'css3' },
{ name: 'ruby' },
{ name: 'rails' },
{ name: 'python' },
{ name: 'html' }
])
And then you'll have to seed your database with rake:db seed.

Resources