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
Related
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' }
]
}
]
I use angular5-csv to create and download csv file from my data.
Is there a way to create multiple sheets?
for example I have 2 objects : data1 and data2, and I want that each object will be displayed in a separate sheet.
var data1 = [
{
name: "Test 1",
age: 13,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
{
name: 'Test 2',
age: 11,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
{
name: 'Test 4',
age: 10,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
];
var data2 = [
{
name: "Test 1",
age: 13,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
{
name: 'Test 2',
age: 11,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
{
name: 'Test 4',
age: 10,
average: 8.2,
approved: true,
description: "using 'Content here, content here' "
},
];
I want to download each data array in two different sheets in a single file
I have a query from sequel that is returning something like this:
posts = [
<Post: #attributes={ id: 1, title: 'Foo', text: 'Bar', user_id: 21, user: <User: #attributes={ id: 21, name: 'John'}>}>,
<Post: #attributes={ id: 2, title: 'Bar', text: 'Foo', user_id: 21, user: <User: #attributes={ id: 21, name: 'John'}>}>,
<Post: #attributes={ id: 3, title: 'FooBar', text: 'FooBar', user_id: 19, user: <User: #attributes={ id: 19, name: 'Jane'}>}>
]
An array of Post and User objects.
I want to return it like this to the user:
json = {
posts:[
{ id: 1, title: 'Foo', text: 'Bar', user_id: 21 },
{ id: 2, title: 'Bar', text: 'Foo', user_id: 21 },
{ id: 3, title: 'FooBar', text: 'FooBar', user_id: 19 }
],
users: [
{ id: 21, name: 'John'},
{ id: 19, name: 'Jane'}
]
}
What would be the most efficient way to extract this Hash from the original array?
This is the code I'm using for it right now:
def prepare_json(array)
posts = []
users = Hash[]
array.each do |item|
posts.push(item.post)
# user id is unique so I use it to avoid duplication on
# the users array
users[item.user.id.to_sym] = item.user
end
{ posts: posts, users: users.values }
end
users = posts.map{|h| h.delete(:user)}.uniq
json = {posts: posts, users: users}
Result:
{
:posts=>[{:id=>1, :title=>"Foo", :text=>"Bar", :user_id=>21}, {:id=>2, :title=>"Bar", :text=>"Foo", :user_id=>21}, {:id=>3, :title=>"FooBar", :text=>"FooBar", :user_id=>19}],
:users=>[{:id=>21, :name=>"John"}, {:id=>19, :name=>"Jane"}]
}
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"
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"]