NameError: uninitialized constant on seed.rb - ruby-on-rails

While doing the seed.rb for my app I came across the following error when running rake db:seed:
rake aborted!
NameError: uninitialized constant Menu::CourseMenu
C:in `destroy_all'
C:.../db/seeds.rb:11:in `<top (required)>'
Tasks: TOP => db:seed
(See full trace by running task with --trace)
Menu:
class Menu < ActiveRecord::Base
belongs_to :user
has_many :course_menus, dependent: :destroy
end
CoursesMenu:
class CoursesMenu < ActiveRecord::Base
belongs_to :menu
has_and_belongs_to_many :recipes, dependent: :destroy
end
Seed.rb:
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
User.destroy_all
Menu.destroy_all
CookBook.destroy_all
CoursesMenu.destroy_all
Recipe.destroy_all
User.create! [
{ email: "jean#mail.com", password: "12345", status: true },
{ email: "wendy#mail.com", password: "12345", status: true },
{ email: "jose#mail.com", password: "12345", status: true },
{ email: "vivi#mail.com", password: "12345", status: true },
{ email: "emilio#mail.com", password: "12345", status: true }
]
sample_menus = Menu.create! [
{ name: "For Mom", description: "Menu to lose weight" },
{ name: "For Dad", description: "Menu to gain more muscle" },
{ name: "For the lil tykes", description: "Menu so they stop being fat" },
{ name: "For the Vegan Aunt", description: "For the old harpy" }
]
sample_cookbooks = CookBook.create! [
{ name: "Jean'selections", description: "Premiun choices by Jean" },
{ name: "Wendy'selections", description: "Premiun choices by Wendy" },
{ name: "Jose'selections", description: "Premiun choices by Jose" },
{ name: "Best of All", description: "JPremiun choices by the Crew" }
]
sample_recipes = Recipe.create! [
{ img_url: "http://static.food2fork.com/BrownieFeature193f.jpg", title: "Slutty Brownies", source_url: "http://whatsgabycooking.com/slutty-brownies/"},
{ img_url: "http://static.food2fork.com/pizza292x2007a259a79.jpg", title: "Homemade Pizza", source_url: "http://www.simplyrecipes.com/recipes/homemade_pizza/" },
{ img_url: "http://static.food2fork.com/5337400468_d5892f3a03_od5cd.jpg", title: "Chicken Tortilla Soup", source_url: "http://thepioneerwoman.com/cooking/2011/01/chicken-tortilla-soup/"},
{ img_url: "http://static.food2fork.com/GuacamoleGrilledCheese6019.jpg", title: "Guacamole Grilled Cheese Sandwich", source_url: "http://www.twopeasandtheirpod.com/guacamole-grilled-cheese-sandwich/"}
]
sample_courses_menus = CoursesMenu.create! [
{ course_name: "Breakfast", day: "Monday" },
{ course_name: "Day Snack", day: "Monday" },
{ course_name: "Lunch", day: "Monday" },
{ course_name: "Dinner", day: "Monday" },
{ course_name: "Night Snack", day: "Monday" },
{ course_name: "Breakfast", day: "Tuesday" },
{ course_name: "Day Snack", day: "Tuesday" },
{ course_name: "Lunch", day: "Tuesday" },
{ course_name: "Dinner", day: "Tuesday" },
{ course_name: "Night Snack", day: "Tuesday" },
{ course_name: "Breakfast", day: "Wednesday" },
{ course_name: "Day Snack", day: "Wednesday" },
{ course_name: "Lunch", day: "Wednesday" },
{ course_name: "Dinner", day: "Wednesday" },
{ course_name: "Night Snack", day: "Wednesday" },
{ course_name: "Breakfast", day: "Thursday" },
{ course_name: "Day Snack", day: "Thursday" },
{ course_name: "Lunch", day: "Thursday" },
{ course_name: "Dinner", day: "Thursday" },
{ course_name: "Night Snack", day: "Thursday" },
{ course_name: "Breakfast", day: "Friday " },
{ course_name: "Day Snack", day: "Friday " },
{ course_name: "Lunch", day: "Friday " },
{ course_name: "Dinner", day: "Friday " },
{ course_name: "Night Snack", day: "Friday " },
{ course_name: "Breakfast", day: "Saturday" },
{ course_name: "Day Snack", day: "Saturday" },
{ course_name: "Lunch", day: "Saturday" },
{ course_name: "Dinner", day: "Saturday" },
{ course_name: "Night Snack", day: "Saturday" },
{ course_name: "Breakfast", day: "Sunday" },
{ course_name: "Day Snack", day: "Sunday" },
{ course_name: "Lunch", day: "Sunday" },
{ course_name: "Dinner", day: "Sunday" },
{ course_name: "Night Snack", day: "Sunday" }
]
sample_cookbooks. << 20.times { |index| CookBook.create! name: "CookBook#{index}", description: "This is a cookbook sample #{index}" }
CoursesMenu.all.each do |course_menu|
course_menu.recipes = sample_recipes.sample
course_menu.save!
end
Menu.all.each do |menu|
menu.course_menus = sample_courses_menus.sample
menu.save!
end
CookBook.all.each do |book|
book.recipes = sample_recipes.sample
book.save!
end
User.all.each do |user|
user.cook_books = sample_cookbooks.sample
user.menus = sample_menus.sample
user.save!
end
I suspect there is something I'm handling wrong with the relationship because if I change destroy_all to delete_all in the seed.rb this particular error doesn't occur.
I was hopping someone could point me in the right direction to solve this.

In your Menu model, change
has_many :course_menus, dependent: :destroy
to
has_many :courses_menus, dependent: :destroy
Would it be a more correct inflection to define the CoursesMenu as CourseMenu? If so your association would be correct as is.
Also, FYI, the reason destroy_all fails and delete_all works is because destroy_all deletes each record individually, executing callbacks (including dependent: :destroys) in the process. This is where the error occurs because Rails tries to use a model of type CourseMenu which doesn't exist the way you have defined your classes. In contrast, delete_all simply deletes the records in question, in one query (DELETE from menus), and does not try to execute any callback code, so Rails never encounters the mis-named resource.

Problem
Menu has many :course_menus
but your class is
CoursesMenu
Solution
You could just rename CoursesMenu to Course, and Menu would have many :courses.
Whatever you choose, you could check the names are correct :
:courses.to_s.capitalize.singularize
#=> "Course"
:course_menus.to_s.camelcase.singularize
#=> "CourseMenu"

Related

Get all objects that has an array that contains a specific value

I have an array of objects called students that looks like this:
[
{
student_id: '1',
student_name: 'student 1',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'asdf9d2d', course_name: 'courses 2'},
{ course_id: 'h355dsf4', course_name: 'courses 3'}
]
},
{
student_id: '2',
student_name: 'student 2',
courses: [
{ course_id: 'asdf9d2d', course_name: 'courses 2'},
{ course_id: 'glld9432d2', course_name: 'courses 4' }
]
},
{
student_id: '3',
student_name: 'student 3',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'glld9432d2', course_name: 'courses 4' }
]
}
]
I am trying to figure out the best way to get all objects that contain a specific course id.
I tried students.where(courses.course_id == "dxgk22452") with no luck and could not find a post with my specific situation.
What would be the best way to go about this?
You can iterate twice to select those hashes, where their courses include at least one hash where its course_id is equal to dxgk22452:
data.select { |e| e[:courses].find { |f| f[:course_id] == 'dxgk22452' } }
Given an array:
students = [
{
student_id: '1',
student_name: 'student 1',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'asdf9d2d', course_name: 'courses 2'},
{ course_id: 'h355dsf4', course_name: 'courses 3'}
]
},
{
student_id: '2',
student_name: 'student 2',
courses: [
{ course_id: 'asdf9d2d', course_name: 'courses 2'},
{ course_id: 'glld9432d2', course_name: 'courses 4' }
]
},
{
student_id: '3',
student_name: 'student 3',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'glld9432d2', course_name: 'courses 4' }
]
}
]
Return the students whose courses include the given value:
students.select { |student| student[:courses].any? { |course| course[:course_id] == 'dxgk22452' } }
=> [
{
student_id: '1',
student_name: 'student 1',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'asdf9d2d', course_name: 'courses 2'},
{ course_id: 'h355dsf4', course_name: 'courses 3'}
]
},
{
student_id: '3',
student_name: 'student 3',
courses: [
{ course_id: 'dxgk22452', course_name: 'courses 1' },
{ course_id: 'glld9432d2', course_name: 'courses 4' }
]
}
]

Ruby on Rails 5, Active Record Associations, API ONLY

I am working on a react native application and as part of the project I am building an API using Ruby on Rails 5 in API Only mode with ActiveAdmin for the admin interface. I have everything setup, and it's all working well.
I was given the data in a file before having the idea of an API, the structure of which I need to replicate using rails, this is so it can be content manageable.
But I can't seem to get the active record associations correct.
This is a sample of the data file...
{
name: 'Scottish Stoics',
days: [
{
day: 'Monday',
meeting: [
{
name: 'Meeting one',
location: 'Test',
startTime: '11.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting two',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting three',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
],
},
{
day: 'Tuesday',
meeting: [
{
name: 'Meeting one',
location: 'Test',
startTime: '10',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting two',
location: 'Test',
startTime: '10',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting three',
location: 'Test',
startTime: '10',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
],
},
],
},
{
name: 'Scottish Cycling Group',
days: [
{
day: 'Sunday',
meeting: [
{
name: 'Meeting one',
location: 'Test',
startTime: '11.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting two',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting three',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
],
},
{
day: 'Tuesday',
meeting: [
{
name: 'Meeting one',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting two',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
{
name: 'Meeting three',
location: 'Test',
startTime: '10.00',
address: 'Test Street',
meetingLength: '1 Hour',
city: 'Edinburgh',
},
],
},
],
}
I have a Group Model, Day Model and a Meeting Model.
Group
belongs_to :day
belongs_to :meeting
Meeting
has_many :groups
Day
has_many :groups
And I am getting this result.
[
{
id: 1,
name: "Scottish Stoics",
created_at: "2018-03-19T11:47:50.818Z",
updated_at: "2018-04-12T10:50:05.179Z",
day_id: 7,
meeting_id: 81
},
{
id: 2,
name: "Scottish Cycling Group",
created_at: "2018-03-19T11:47:57.498Z",
updated_at: "2018-04-11T22:13:26.656Z",
day_id: 7,
meeting_id: 83
},
]
Now I can use jbuilder to get the day name and meeting name which is fine, but what I can't do is select MULTIPLE meetings for one day, and MULTIPLE DAYS for the group. Is this data structure even going to be possible in Rails?
I can't work out if I should be using a different type of association, anyone able to shed some light on this for me?
Assuming that the top level nesting corresponds to Group you can form the associations like that:
Day
has_many :meetings
belongs_to :group
Meeting
belongs_to :day
Group
has_many :days
has_many :meetings, through: :days
Though i have the impression that in the JSON provided it should be meetings rather than meeting to keep it RESTful

Get objects only within one array and not multiple arrays within an array

Sorry for the bad English Title but the code below would make more sense.
I used .each to get some keys and values that I wanted from the data but when I do it I get this result.
[
[
{
id: 1,
name: "Immad",
age: 18
}
],
[
{
id: 2,
name: "Vicky",
age: 21
}
],
[
{
id: 3,
name: "Adam",
age: 24
}
]
]
I want to map the objects to some js library for which I want it to be like:
[
{
id: 1,
name: "Immad",
age: 18
},
{
id: 2,
name: "Vicky",
age: 21
},
{
id: 3,
name: "Adam",
age: 24
}
]
Can anybody please atleast give me hint what should I use in order to do it using ruby. Thanks in advance.
There already is an Array method.
foo_array.flatten!
or non destructive (just a return value foo_array remains unchanged)
foor_array.flatten
Simple, You should do like this
Test = [[{:id=>1, :name=>"Immad", :age=>18}], [{:id=>2, :name=>"Vicky", :age=>21}], [{:id=>3, :name=>"Adam", :age=>24}]]
Use .flatten here.
Test.flatten
=> [{:id=>1, :name=>"Immad", :age=>18}, {:id=>2, :name=>"Vicky", :age=>21}, {:id=>3, :name=>"Adam", :age=>24}]
Use .map!:
foo = [
[
{
id: 1,
name: "Immad",
age: 18
}
],
[
{
id: 2,
name: "Vicky",
age: 21
}
],
[
{
id: 3,
name: "Adam",
age: 24
}
]
]
# Call .map! on the array
foo.map! { |array| array.first }
=> [
[0] {
:id => 1,
:name => "Immad",
:age => 18
},
[1] {
:id => 2,
:name => "Vicky",
:age => 21
},
[2] {
:id => 3,
:name => "Adam",
:age => 24
}
]

how to covert array object to hash in rails

i have a hash with array object :
{
false=>[#<Campaign id: 1, name: "campaign 1", active: false>, #<Campaign id: 3, name: "campaign 3", active: false>, #<Campaign id: 4, name: "campaign 4", active: false>],
true=>[#<Campaign id: 2, name: "campaign 2", active: true>]
}
how to convert above hash to hash
{
false=>[{id:1, name:"campaign 1"}, {id:3, name: "capaign 3"}, ....],
true =>[{id:2, name:"campaign 2"}]
}
hash.each {|k,v| hash[k] = v.map{|e| {id: e[:id], name: e[:name]}}}
and if you can use select_all method get the array of hash, not array of object, so you doesn't need to covert object to hash.
ModelName.connection.select_all("select id, name from <table_name>;")
=> [{id:xxx, name: xxx}.......]
Use attributes method on your object
attributes() public
Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
hash = {
false => [#<Campaign id: 1, name: "campaign 1", active: false>, #<Campaign id: 3, name: "campaign 3", active: false>, #<Campaign id: 4, name: "campaign 4", active: false>],
true => [#<Campaign id: 2, name: "campaign 2", active: true>]
}
So this line should do the trick -
hash.each {|k, v| hash[k] = v.map(&:attributes) }
{
false => [{"id": 1, "name": "campaign 1", "active": false}, {"id": 3, "name": "campaign 3", "active": false}, {"id": 4, "name": "campaign 4", "active": false}],
true => [{"id": 2, "name": "campaign 2", "active": true}]
}

Group orderring

I am looking to group a list of projects by a nested field, in this case custom_field.value when a certain id is passed in.
[{
id: 1,
name: "project one ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2010"
},
{
id: 5,
name: "Priority",
value: "low"
},
]},
{
id: 2,
name: "project two ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2011"
},
{
id: 5,
name: "Priority",
value: "medium"
},
]},
{
id: 3,
name: "project three ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2012"
},
{
id: 5,
name: "Priority",
value: "high"
},
]}]
So if the params[:id] == 4 I want the list to be ordered by the custom_field id's corresponding value in decending order.
So in this case they would be ordered.
2012
2011
2010
Any ideas?
Is this what you are looking for? Your question is a bit unclear but I think this should suffice:
Your Original Hash:
test = [{
id: 1,
name: "project one ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2010"
},
{
id: 5,
name: "Priority",
value: "low"
},
]},
{
id: 2,
name: "project two ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2011"
},
{
id: 5,
name: "Priority",
value: "medium"
},
]},
{
id: 3,
name: "project three ",
custom_fields: [
{
id: 4,
name: "Year",
value: "2012"
},
{
id: 5,
name: "Priority",
value: "high"
},
]}]
Use group_by and sort(with handling for elements where there is no id found):
def group_and_sort(test_hash,id)
test_hash.group_by do |g|
elem = g[:custom_fields].detect {|h| h[:id] == id}
elem ? elem[:value] : "0"
end.sort.reverse.to_h
end
Then call like:
group_and_sort(test,4)
#=>{"2012"=>
[{:id=>3,
:name=>"project three ",
:custom_fields=>
[{:id=>4, :name=>"Year", :value=>"2012"},
{:id=>5, :name=>"Priority", :value=>"high"}]}],
"2011"=>
[{:id=>2,
:name=>"project two ",
:custom_fields=>
[{:id=>4, :name=>"Year", :value=>"2011"},
{:id=>5, :name=>"Priority", :value=>"medium"}]}],
"2010"=>
[{:id=>1,
:name=>"project one ",
:custom_fields=>
[{:id=>4, :name=>"Year", :value=>"2010"},
{:id=>5, :name=>"Priority", :value=>"low"}]}]}
Assume projects is the data you pasted.
def order_values_by_id(pjs, id)
pjs.map{|p| p[:custom_fields].find{|f| f[:id] == id}[:value] }.sort.reverse
end
order_values_by_id(projects)
#=> ["2012", "2011", "2010"]

Resources