Test in Rails console model associations? - ruby-on-rails

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.

Related

How to get fields from has_many :throught association

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.

Rails - Associate three Models

Having three models: Datum, Author, and Book .
class Datum < ApplicationRecord
has_many :authors
end
class Book < ApplicationRecord
belongs_to :author
end
class Author < ApplicationRecord
belongs_to :datum
has_many :books, dependent: :destroy
end
For exercise purpose, I wanted to model it that Datum(more general), can have many authors, which can have books.
After creating a datum object and an associated author for it, I could call nameofdatum.authors, but if I added a book to that author, it could not be recognized through nameofdatum.authors.books. Am I having wrong expectations ? (Should this be done with 'through'(an explanation of it would be much appreciated)
(Schema here if needed)
create_table "authors", force: :cascade do |t|
t.string "name"
t.integer "age"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "book_id"
t.integer "datum_id"
t.index ["book_id"], name: "index_authors_on_book_id"
t.index ["datum_id"], name: "index_authors_on_datum_id"
end
create_table "books", force: :cascade do |t|
t.string "name"
t.string "book_type"
t.integer "pages"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "author_id"
t.index ["author_id"], name: "index_books_on_author_id"
end
create_table "data", force: :cascade do |t|
t.string "region"
t.integer "budget"
t.date "aval"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Should this be done with 'through'?
Yes, Datum has_many books through the authors assocition:
class Datum < ApplicationRecord
has_many :authors
has_many :books, through: :authors
end
And the books can be selected via:
Datum.last.books
It's actually selects books using the following query:
SELECT "books".* FROM "books" INNER JOIN "authors" ON "authors"."id" = "books"."author_id" WHERE "authors"."datum_id" = ?
If you want to add a new book through author, you have to assign an author. So you can try:
nameofdatum.author.books.build ....
your codenameofdatum.authors.books, you can't use a plural(author) to add a new book.
Hope to help you.

Proper way to add a non standard foreign key to my model? Ruby on Rails

I have a table that needs to reference another table without using the id column for the foreign key.
I have these two models:
class MatchReference < ApplicationRecord
belongs_to :summoner, :foreign_key => 'accountId'
end
class Summoner < ApplicationRecord
has_many :match_references
end
I created this migration to link them together with a Summoner.accountId:
class AddAccountIdToMatchReferences < ActiveRecord::Migration[5.1]
def change
add_reference :match_references, :summoner, column: :accountId, foreign_key: true
end
end
Note that the foreign key that match_references should use is summoners.accountId and NOT summoners.id
I get this schema after running the migrations:
create_table "match_references", force: :cascade do |t|
t.string "lane"
t.bigint "gameId"
t.integer "champion"
t.string "platformId"
t.integer "season"
t.integer "queue"
t.string "role"
t.bigint "timestamp"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "summoner_id"
t.index ["summoner_id"], name: "index_match_references_on_summoner_id"
end
create_table "summoners", force: :cascade do |t|
t.bigint "profileIconId"
t.string "name"
t.integer "summonerLevel"
t.datetime "revisionDate"
t.bigint "league_id"
t.bigint "accountId"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
and I want to be able to do something like:
s = Summoner.last
s.match_references.last.gameId # => 123456789
m = MatchReference.new
m.summoner_id = s.accountId
m.game_id = 1234
m.champion = 123
...
m.save!
But I get an error saying:
ActiveRecord::RecordInvalid: Validation failed: Summoner must exist
from /Users/hebrongeorge/.rvm/gems/ruby-2.4.1/gems/activerecord-5.1.4/lib/active_record/validations.rb:78:in `raise_validation_error'
This should work:
class Summoner < ApplicationRecord
self.primary_key = 'accountId'
has_many :match_references, :foreign_key => 'accountId'
end
class MatchReference < ApplicationRecord
belongs_to :summoner
end

How to show multiple ids to a table in rails

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

Rails association in model error

I am using rails 4.2.0. and I am getting this error:
ActiveRecord::HasManyThroughAssociationNotFoundError:
Could not find the association :taggings in model Article
Here are my models:
class Tag < ActiveRecord::Base
has_many :taggings
has_many :articles, :through => :taggings
end
class Article < ActiveRecord::Base
has_many :comments
has_many :taggings
has_many :tags, :through => :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :article
end
Tagging is an intermediary model for the many-to-many relationship between Article and Tag.
And if it helps, my schema:
ActiveRecord::Schema.define(version: 20150224161732) do
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", force: :cascade do |t|
t.string "author_name"
t.text "body"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["article_id"], name: "index_comments_on_article_id"
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "taggings", ["article_id"], name: "index_taggings_on_article_id"
add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id"
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I run this code in rails console to test my associations:
a = Article.first
a.tags.create name: "cool"
And I get the above error.
I have seen similar questions where the response "if you have through: :x, you have to have has_many :x first," but I don't think that is my issue.
This might be a silly question, but have you tried creating a Tagging independent of the Article model? If you haven't, than it could be something messed up with the database not having the Tagging model. Otherwise, associations look fine and should work. The only other thing I can think of is incorrect file names for your models folder

Resources