I'm using Chartkick in my RoR app and I'm trying to create a pie chart that displays all the People that are in each Group. My Group and Person model are both HABTM. Right now the chart is working and only displaying number of groups(screenshot and code below) if someone knows how to grab the number of people in each group using active record I'd love it!
here is my code
<%= pie_chart Group.group(:name).count %>
Here is a screenshot
here is my Schema
create_table "people", force: :cascade do |t|
t.string "phone_number"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "subscribed", default: true, null: false
t.string "city"
t.string "state"
t.string "zip"
t.string "country"
end
create_table "groups", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "groups_people", id: false, force: :cascade do |t|
t.integer "group_id", null: false
t.integer "person_id", null: false
end
here is the person model
class Person < ActiveRecord::Base
has_many :deliveries
has_and_belongs_to_many :groups
here is group model
class Group < ActiveRecord::Base
has_and_belongs_to_many :people
has_and_belongs_to_many :messages
end
<%= pie_chart Group.includes(:people).all.map {|g| [g.name, g.people.size] }.to_h %>
By the way, it will better to move this logic into model body.
Related
I want to fetch sku_code from products, wh_name from warehouses table and item_count from product_warehouses.
I tried something like
Product.all.includes(:product_warehouses)
But not working :(
Below are the schema of my tables
create_table "product_warehouses", force: :cascade do |t|
t.integer "product_id"
t.integer "warehouse_id"
t.integer "item_count"
t.integer "threshold"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_product_warehouses_on_product_id"
t.index ["warehouse_id"], name: "index_product_warehouses_on_warehouse_id"
end
create_table "products", force: :cascade do |t|
t.string "sku_code"
t.string "name"
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "warehouses", force: :cascade do |t|
t.string "wh_code"
t.string "wh_name"
t.string "pin"
t.integer "max_cap"
t.integer "threshold"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Below are the relationship between tables:
class Product < ApplicationRecord
has_many :product_warehouses
has_many :warehouses, through: :product_warehouses
end
class ProductWarehouse < ApplicationRecord
belongs_to :product
belongs_to :warehouse
end
class Warehouse < ApplicationRecord
has_many :product_warehouses
has_many :products, through: :product_warehouses
end
If you want to load all three records with a single query, use eager_load:
Product.all.eager_load(:product_warehouses, :warehouses)
Let's say you want to print sku_code, wh_name, and item_count in the console. First load all the products into variable:
products = Product.all.eager_load(:product_warehouses, :warehouses)
Then loop through the records and print out each of the values:
products.each do |product|
puts "sku_code: #{product.sku_code}"
product.product_warehouses.each do |product_warehouse|
puts "item_count: #{product_warehouse.item_count}"
puts "wh_code: #{product_warehouse.warehouse.wh_code}"
end
end
I am still relatively new to Active Record and have a (hopefully simple) question.
I have four tables Recipes(Name of recipe), Food(lettuce, Pepper), Units(oz, tbsp), and Ingredients(Id's of the other tables and the numeric quantity).
What I'd like to do is something like this Recipes.Ingredients and get "Peppered Lettuce, 5 tbsp pepper, 10 oz Lettuce".
How would I accomplishes that with the following schema. And if not possible with this schema what should I build in its place.
The Schema looks like this:
create_table "food", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "ingredients", force: :cascade do |t|
t.bigint "recipes_id"
t.bigint "units_id"
t.bigint "food_id"
t.decimal "quantity"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["food_id"], name: "index_ingredients_on_food_id"
t.index ["recipes_id"], name: "index_ingredients_on_recipes_id"
t.index ["units_id"], name: "index_ingredients_on_units_id"
end
create_table "recipes", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
create_table "units", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
so what I understand from your question is you want to get results like:
Peppered Lettuce, 5 tbsp pepper, 10 oz Lettuce in which Peppered Lettuce is Recipe name, and Pepper and Lettuce are Food items with numeric quantities of ingredients.
You don't need 4 tables to obtain this result. You only need 3. Food, Recipe and an in-between table for their many-to-many association.
Recipe can have multiple Food items in it and 1 Food item can be a part of multiple Recipe objects. So Food and Recipe model will have a many-to-many association. And for this kind of association, you need another table. You can name it Foods_Recipes or simply Ingredients.
Your Ingredient model will then have a food_id,recipe_id,numeric_quantity and unit_type
The Schema would look like this:
create_table "foods", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "ingredients", force: :cascade do |t|
t.bigint "recipe_id"
t.bigint "food_id"
t.decimal "quantity"
t.string "unit_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["food_id"], name: "index_ingredients_on_food_id"
t.index ["recipe_id"], name: "index_ingredients_on_recipe_id"
end
create_table "recipes", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
Your models would look like this:
Food model:
class Recipe < ApplicationRecord
has_many :ingredients
has_many :foods,through: :ingredients
end
Ingredient model:
class Ingredient < ApplicationRecord
belongs_to :recipe
belongs_to :food
end
Food model:
class Food < ApplicationRecord
has_many :ingredients
has_many :recipes,through: :ingredients
end
I have a problem, I want to create an hashtags system, but when I run my code, and when I want to create a travel that contain hashtags I have this error :
ActiveRecord::StatementInvalid in TravelsController#create
Could not find table 'tags_travels'
Here is my travel.rb
class Travel < ApplicationRecord
has_many :posts
belongs_to :user
has_and_belongs_to_many :tags
#after / before create
after_create do
travel = Travel.find_by(id: self.id)
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
before_update do
travel = Travel.find_by(id: self.id)
travel.tags.clear
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
end
my tag.rb
class Tag < ApplicationRecord
has_and_belongs_to_many :travels
end
the schema.rb file (just table concerned) :
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.string "text"
t.string "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
create_table "travels", force: :cascade do |t|
t.string "name"
t.string "trip_type"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "hashtags"
end
create_table "travels_tags", id: false, force: :cascade do |t|
t.integer "travel_id"
t.integer "tag_id"
t.index ["tag_id"], name: "index_travels_tags_on_tag_id"
t.index
["travel_id"], name: "index_travels_tags_on_travel_id"
end
Someone has a solution ? Thank !
Rails looks for join tables in a specific syntax. Its trying to find tags_travles but uouve created it with travels_tags.
Change your model associations to specify the join table.
has_and_belongs_to_many :travels, :join_table => :travels_tags
And
has_and_belongs_to_many :tags, :join_table => :travels_tags
Heres some info from the docs to help explain the defsult behaviour for join table naming.
"By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order."
http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-join-table
I am relatively new to RoR.
This works nicely:
<td><%= collection_select :competitions_members, :member_id, Member.all, :id, :first_name %></td>
This one picks no value (actually all such calls to tables with translations):
<td><%= collection_select :competitions_members, :tull_id, Tull.all, :id, :name %></td>
seeded data in competitions_members table
Member can be involved in many competition. Basically I have N:M relationship between members and competitions via competitions_members table.
Tull is a dictionary. Value to be set during the process of assigning members to a competition.
Data model classes:
class Member < ApplicationRecord
has_and_belongs_to_many :competitions
end
class Competition < ApplicationRecord
has_and_belongs_to_many :members
end
class CompetitionsMember < ApplicationRecord
end
Tull table has also translations in separate table.
class Tull < ApplicationRecord
translates :name
has_many :competitions_members
# separate different localizations of the record
def cache_key
super + '-' + Globalize.locale.to_s
end
end
Relevant schema.db excerpt
create_table "members", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "competitions_members", force: :cascade do |t|
t.integer "member_id"
t.integer "competition_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "tull_id"
t.index ["tull_id"], name: "index_competitions_members_on_tull_id"
end
create_table "tull_translations", force: :cascade do |t|
t.integer "tull_id", null: false
t.string "locale", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.index ["locale"], name: "index_tull_translations_on_locale"
t.index ["tull_id"], name: "index_tull_translations_on_tull_id"
end
create_table "tulls", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Any help apreciated. I just realized this might be connected with translated tables somehow.
class Tull < ApplicationRecord
has_many :translations
translates :name, :fallbacks_for_empty_translations => true
attr_accessible :translations_attributes
end
Try to execute below code in rails console:
Tull.first.translations - If this gives you translation records that means the associations are correct.
Now check at view side, how would you generate attributes for multilingual stuffs. I would suggest to use globalize_accessors.
Please send me the codebase.
I'm rails begginer.
how to load database that has following condition.
I want show lecture list that has order by comment.created_at DESC
schema.rb
create_table "comments", force: :cascade do |t|
t.text "content"
t.integer "user_id"
t.integer "lecture_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "likedcount", default: 0
end
create_table "lectures", force: :cascade do |t|
t.string "subject"
t.string "professor"
t.string "major"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "uptachi", default: 0
t.integer "hatachi", default: 0
end
lecture.rb
has_many :comments
comment.rb
belongs_to: lectures
You need to write it as:
has_many :comments, -> { order("comments.created_at DESC") }
As per the OP's comment, it seems, what he want is a named scope. Like,
scope :order_by_comments, -> { joins(:comments).order("comments.created_at DESC") }