I have 3 models (Genre, Mood, Tempo) each with a has_and_belongs_to_many association with another model (Track). The user can upload an Excel file with info for each track and I want to be able to create the respective records and add the association all at once in my update method.
I'm reading each row from the spreadsheet and creating arrays holding the genres, moods, and tempos that are to be associated with each track, but I'm not sure how to correctly create the association.
Something like:
1.upto #worksheet.last_row_index do |index|
row = #worksheet.row(index)
genres = row[6].split(", ")
genres.each do |g|
Genre.find_or_create_by_name(g) // not sure what to do here exactly
end
end
The Track ID is row[0].
I need to create each Genre if it doesn't exist, and associate that track with each. If the genre does exist, then I just need to create the association. Same for moods and tempos.
Thanks for any assistance.
This seems to do it.
1.upto #worksheet.last_row_index do |index|
row = #worksheet.row(index)
track = Track.find(row[0])
genres = row[6].split(", ")
genres.each do |g|
track.genres << Genre.find_or_create_by_name(g)
end
end
Related
I have this code:
Business.all.limit(50).each do |business|
card = {name: business.name, logo: business.logo, category: business.category.name}
feed << card
end
In my models, Business belongs to Category, and Category has many Business
My problem is that this will query the DB 50 times, each time I want to retrieve each business' category name.
I have seen Rails cache effectively by using :include, but all examples I have seen are for child records, for example:
Category.all :include => [:businesses]
but in this case I want to cache the parent's data.
Its the same you can do by using singular model name
Business.includes(:category)
I have two tables:
Venues
has_many :venue_intel_maps
VenueIntelMap
belongs_to :venue
In the venue_intel_map table there's a column called :tag_label that I want to grab for each particular venue that has a venue_intel_map
In my controller below this returns an array of each venue where then each venue has a venue_id
def show
#venues = Venue.where(parent_venue_id: current_admin.parent_venue_id)
end
So in my views, I can do this for particular venue.
- #venues.each do |venue|
=venue.name
=venue.address
=venue.location
But because I want to get to venue_intel_maps table so I can call a column called :tag_label I wanted to avoided a nested each statement that might look something like this
- #venues.each do |venues|
- venues.venue_intel_maps.each do |intel_maps|
= intel_maps.tag_label
Is there anyway I can clean this up or any suggestions? I was trying to play around with .joins or .selects in active record but didn't know how to successfuly do that so I can somehow put the logic in my Venues model.
EDIT
Would it also be better somehow to define in the controller my venue doing this? In the views I'm going to be pulling things from my venue_intel_maps table so would this serve any advantage?
#venues = Venue.joins(:venue_intel_maps).where(parent_venue_id: current_admin.parent_venue_id)
depending on your Rails version, try:
#venues.venue_intel_maps.pluck(:tag_label)
#venues.venue_intel_maps.map(&:tag_label)
see: http://rubyinrails.com/2014/06/rails-pluck-vs-select-map-collect/
You could preload (Rails 3+) the venue_intel_maps in the controller
def show
#venues = Venue.where(
parent_venue_id: current_admin.parent_venue_id
).preload(:venue_intel_maps)
end
Then in the view, use the iteration you suggested
- #venues.each do |venue|
= venue.name
= venue.address
= venue.location
= venue.venue_intel_maps.each do |intel_maps|
= intel_maps.tag_label
I want to push dummy content in my database. There is a 1:n relationship concepted in my models.
seeds.rb:
city= City.create([{:ort_name=>"Hagen"}])
person= Person.create([{:name = "root"}])
I try this
city << person
and
person.city_id = city.id
How would you do this?
Your question is a bit vague. It seems like you have a relationship where a city has many people. If so, then you can assign the relationship like this:
city.people << person
or this
person.city_id = city.id
person.save
This method requires save since assigning the city_id to person does not write the change to the database.
You can try these out in your rails console
I have a table of recipes, a table of ingredients and an association table (a recipe "has and belong to many" ingredient and an ingredient "has and belongs to many" recipe).
I do not have a controller or a model for the association table.
I want to write a task that fills the association table with random (yet valid) data.
I wrote a code that generates the valid ids for the association table, but I couldn't figure how to get it to go in the association table (since I don't have its model).
Can I somehow iterate over the recipes, and add the data to the recipe.ingredients list? Will it automatically fill the association table?
My code so far:
namespace :FillRandomAssociationData do
desc "Fills the recipes - ingredients association table with random data"
task :Recipe_Ingredients_Association => :environment do
Recipe.all.each do |rec|
numOfIngredientsPerRecipe = rand(3)
ingredientIDLimit = Ingredient.count
for i in 0..numOfIngredientsPerRecipe
ingRandId = rand(ingredientIDLimit)
.... This is where I got stuck...
end
end
end
end
Thanks,
Li
You just have to fill the recipe object with its ingredients, and save it, Rails will fill the association table:
desc "Fills the recipes - ingredients association table with random data"
task :Recipe_Ingredients_Association => :environment do
Recipe.all.each do |rec|
numOfIngredientsPerRecipe = rand(3)
ingredientIDLimit = Ingredient.count
for i in 0..numOfIngredientsPerRecipe
ingRandId = rand(ingredientIDLimit)
rec.ingredients << Ingredient.find(ingRandId)
end
rec.save!
end
end
Be careful, with this algorithm you can add several time the same ingredient to the recipe.
I have an ActiveRecord array containing a list of shops.
shops = Shop.find(:all)
I want to delete a record from shops without deleteting it from the database.
shops.delete(a_shop) would result in a delete SQL query. I just want the shop to be deleted from the ActiveRecord array but not the database.
Can this be done?
Thanks
Beware if you are using has_many relationship the answer by JP will not work.
Extending the example:
class City < ActiveRecord::Base
has_many :shops
end
city = City.find(:name => "Portland")
then
city.shops.delete(city.shops[0])
Will delete from the DB!
Also
theshops = city.shops
theshops.delete(ss[0])
Will delete from the DB
One way to detach from the DB is to use compact or another array function like so:
theshops = city.shops.compact
theshops.delete(ss[0])
Will not delete from the DB
Also, in all cases delete_if Will not delete from the db:
city.shops.delete_if {|s| s.id == city.shops[0]}
Cheers!
Don't forget: If you are in doubt about these sort of things script/console is your friend!
When I did some testing, calling the delete method does not actually delete the element from the database. Only from the array.
shops = Shop.find(:all)
shops.delete(shops[0]) #deletes the first item from the array, not from the DB
To delete from the DB:
shops = Shop.find(:all)
Shop.delete(shops[0].id)
See the distinction? At least, this how it works on my Rails 2.1 setup.
-JP
I don't think you can remove the item from the array.
However, you should be able to modify your find to return the array without that shop initially. Something like:
shops = Shop.find(:all, :conditions => "id NOT #{a_shop.id}")
should be along the lines of what you want. That way you never get the shop in the container in the first place, but it doesn't affect the database.
I would like to suggest such way to delete AR object in memory.
Add an attribute to the appropriate model that is responsible for marking AR object as deleted (e.g. deleted attribute):
class OrderItem < ActiveRecord::Base
...
attr_accessor :deleted
def deleted
#deleted || 'no'
end
end
Mark the appropriate object as deleted:
o.order_items {|oi| oi.deleted = 'yes' if oi.id == 1029}
Filter order_items set only not deleted rows:
o.order_items do |oi|
unless oi.deleted == 'yes'
...
end
end