I am making a Band application where a Venue has many Events and Bands through Events.
I realized that in my form for creating an event can only hold one band_id
but I want to have many bands because it only makes sense to do so.
This is my Schema
ActiveRecord::Schema.define(version: 20170817180728) do
create_table "bands", force: :cascade do |t|
t.string "name"
t.string "genre"
t.string "image"
t.boolean "explicit_lyrics"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "events", force: :cascade do |t|
t.string "name"
t.text "date"
t.boolean "alcohol_served"
t.string "image"
t.integer "venue_id"
t.integer "band_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "venues", force: :cascade do |t|
t.string "name"
t.string "city"
t.string "state"
t.boolean "family_friendly"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
These are my models
class Venue < ApplicationRecord
has_many :events
has_many :bands, through: :events
end
class Event < ApplicationRecord
belongs_to :venue
belongs_to :band
end
class Band < ApplicationRecord
has_many :events
end
I am fairly new to rails this is a practice web app. I want to be able to be able to show multiple band_ids to my event.
Would I just keep repeating t.band_id in my form??
You'll want to specify a foreign key relationship in your migration that reflects the Active Record associations you've set up in your models using belongs_to instead of a data type. This way, you'll get a references from one table to another, or in your case, from one table to two others, which is how one table with two one-to-many relationships is set up.
class CreateEvents < ActiveRecord::Migration
def change
create_table :venues do |t|
t.string :name
t.string :city
t.string :state
t.boolean :family_friendly
t.string :image
t.timestamps
end
create_table :bands do |t|
t.string :name
t.string :genre
t.string :image
t.boolean :explicit_lyrics
t.timestamps
end
create_table :events do |t|
t.belongs_to :venue, index: true # Look here!
t.belongs_to :band, index: true # and here!
t.string :name
t.text :date
t.boolean :alcohol_served
t.string :image
t.timestamps
end
end
end
Related
I've been having trouble to do a challenge with Active Records, I read the documentation, and seen other examples with belongs_to that I remade and worked, I have no clue anymore about what I'm doing wrong here when I try to call recipe.recipe_type.name I get the error Rails NoMethodError: undefined method `name' for "#":String
schema.rb
create_table "recipe_types", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "recipe_type_id"
t.index ["recipe_type_id"], name: "index_recipe_types_on_recipe_type_id"
end
create_table "recipes", force: :cascade do |t|
t.string "title"
t.string "cuisine"
t.string "difficulty"
t.integer "cook_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "ingredients"
t.text "cook_method"
end
end
migrations
def change
create_table :recipes do |t|
t.string :title
t.string :cuisine
t.string :difficulty
t.integer :cook_time
t.timestamps
end
end
end
class AddFieldsToRecipe < ActiveRecord::Migration[5.2]
def change
add_column :recipes, :ingredients, :text
add_column :recipes, :cook_method, :text
end
end
class CreateRecipeTypes < ActiveRecord::Migration[5.2]
def change
create_table :recipe_types do |t|
t.string :name
t.timestamps
end
end
end
class AddRecipeRefToRecipeType < ActiveRecord::Migration[5.2]
def change
add_reference :recipe_types, :recipe_type, foreign_key: true
end
end
You seemed to have added the recipe_type reference to the wrong table. Your last migration should probably have been
add_reference :recipes, :recipe_type, foreign_key: true
because as it is, you have added the reference_type reference to ReferenceType.
So the final schema was:
ActiveRecord::Schema.define(version: 2020_03_26_013134) do
create_table "recipe_types", force: :cascade do |t|
t.string "name"
t.integer "recipe_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["recipe_id"], name: "index_recipe_types_on_recipe_id"
end
create_table "recipes", force: :cascade do |t|
t.string "title"
t.string "cuisine"
t.string "difficulty"
t.integer "cook_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "ingredients"
t.text "cook_method"
t.integer "recipe_type_id"
t.index ["recipe_type_id"], name: "index_recipes_on_recipe_type_id"
end
end
and with
models/recipe_type
class RecipeType < ApplicationRecord
has_many :recipes
end
models/recipe
class Recipe < ApplicationRecord
belongs_to :recipe_type
end
You can start a simple has_many belongs_to active record association, I hope this helps as many people as those who helped me, in the beginning of this journey, strongly recommend to study db:migrate, db:rollback, db:create and db:drop for those who encounter some trouble.
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 have a many-to-many association throught RoomsUsers model and in this model i have a role field, association works well but i can't access this field.
My schema looks like:
create_table "messages", force: :cascade do |t|
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "room_id"
end
create_table "rooms", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "rooms_user_id"
end
create_table "rooms_users", force: :cascade do |t|
t.integer "user_id"
t.integer "room_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "role"
t.integer "last_checked"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "mail"
t.integer "rooms_user_id"
end
User model:
class User < ApplicationRecord
has_secure_password(validations: false)
has_many :messages
has_many :rooms_users
has_many :rooms, through: :rooms_users
accepts_nested_attributes_for :rooms_users
attr_accessor :register, :mail_confirmation, :login
end
Room model:
class Room < ApplicationRecord
has_many :rooms_users
has_many :users, through: :rooms_users
accepts_nested_attributes_for :rooms_users
has_many :message
end
RoomsUsers model:
class RoomsUsers < ApplicationRecord
belongs_to :user
belongs_to :room
end
And i am trying to get role field from first user's room.
User.first.rooms.first.role
It give's me NoMethodError (undefined method `role' for #). What's wrong?
You're trying to access role field in the rooms table, but it is in rooms_users table. Should be:
User.first.rooms_users.first.role
And remove rooms_user_id from rooms and users table, you don't need it
If you want to access "role" field through Rooms model, you will need to change the place of your "role" field from rooms_users table to rooms table. Doing it you can access "role" using User.first.rooms.first.role.
However if you want to keep "role" field in rooms_users table, so you will need to use User.first.rooms_users.first.role as Vasilisa has already mentioned.
t.integer "rooms_user_id" are not necessary in rooms and users tables. The has_many used in rooms and users are already linking rooms_users with them.
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.
Hello I do have this two models and I would like to check that my model associations are working the way it should trough rails console.
I am not able to do the association work. The relationship is the following:
One Event has one rule and one rule belongs to one event. It could not be a rule without an event and it could not be a event without a rule.
Any idea how to test this with rails console?
MODEL 1:
class Event < ActiveRecord::Base
has_and_belongs_to_many :users
has_one :rule
has_many :grand_prixes
belongs_to :eventable, polymorphic: :true
end
MODEL 2
class Rule < ActiveRecord::Base
belongs_to :events
end
Rules' Schema:
create_table "rules", force: :cascade do |t|
t.boolean "abs"
t.boolean "tc"
t.boolean "allow_auto_clutch"
t.boolean "allow_sc"
t.boolean "allow_throttle_blip"
t.boolean "dynamic_track"
t.integer "damage_mult"
t.integer "fuel_rate"
t.integer "tyre_wear_rate"
t.integer "quali_percentage"
t.integer "min_valid_laps"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "rules", ["event_id"], name: "index_rules_on_event_id"
Events' Schema:
create_table "events", force: :cascade do |t|
t.string "event_type"
t.string "name", null: false
t.datetime "starting_date"
t.datetime "ending_date"
t.integer "eventable_id"
t.string "eventable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id"
Thanks in advance.
I think your belongs_to :events should be singular to follow the rails convention :
class Rule < ActiveRecord::Base
belongs_to :event
end
The conventional name of a relation is always singular for belongs_to and has_one, and always plural for has_many.
Related documentation : http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference
EDIT : There much left to say
You wrote :
ev = Event.create(:name "test1").save
rule = Rule.create.save
create is already a new followed by a save. No need to save afterwards.
the syntax key: value is something very common in ruby, and should be well understood : you're actually writing a hash, equivalent to {:key => value}, but the syntax allows you to write key: value ONLY IF your key is a Symbol.
the columns eventable_type and eventable_id should be in the table rules, who is hosting the polymorphic relation with eventable things. Event should not have these columns, and event_id should not exist at all in rules.
Here's an example of what you can write in your console to create an Event and a Rule :
ev = Event.create(name: "test1")
rule = Rule.create(abs: true, event: ev)
Change your code:
class Rule < ActiveRecord::Base
belongs_to :event
end
With belongs_to you should use singular like event not events.
In console you can check association like:
Event.first.rule if Event.first.present?
For more details you should go through http://guides.rubyonrails.org/association_basics.html documentation.
Current code:
class Rule < ActiveRecord::Base
belongs_to :event
end
class Event < ActiveRecord::Base
has_and_belongs_to_many :users
has_one :rule
has_many :grand_prixes
belongs_to :eventable, polymorphic: :true
end
SCHEMA:
create_table "rules", force: :cascade do |t|
t.boolean "abs"
t.boolean "tc"
t.boolean "allow_auto_clutch"
t.boolean "allow_sc"
t.boolean "allow_throttle_blip"
t.boolean "dynamic_track"
t.integer "damage_mult"
t.integer "fuel_rate"
t.integer "tyre_wear_rate"
t.integer "quali_percentage"
t.integer "min_valid_laps"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "rules", ["event_id"], name: "index_rules_on_event_id", unique: true
create_table "events", force: :cascade do |t|
t.string "event_type"
t.string "name", null: false
t.datetime "starting_date"
t.datetime "ending_date"
t.integer "eventable_id"
t.string "eventable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "events", ["eventable_type", "eventable_id"], name: "index_events_on_eventable_type_and_eventable_id"
Tested on console:
ev = Event.create(:name "test1").save
rule = Rule.create.save
No idea how to link it both through console.