I have encountered a problem with my rails console when I try to create a new event based on a user. I have a feeling this is a very simple error that I am getting, but I am posting because I am unsure of how I should fix it. Here is the command I tried to run:
user.event = Event.create(:name => "Dummy")
Here is my db file for my event:
class CreateEvents < ActiveRecord::Migration[5.0]
def change
create_table :events do |t|
t.string :name
t.timestamps
end
end
end
Here is my Users database file:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :event
t.integer :code
t.timestamps
end
end
end
Here is my User.rb file:
class User < ApplicationRecord
has_secure_password
has_many :events
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
end
Here is my Event.rb file:
class Event < ApplicationRecord
belongs_to :user
end
Its not a simple error. It's quite a few things which are wrong.
If you want a relation where a user can have many events, and an event can belong to many users you need to create a join table. As storing a foreign key on either the users or events table would create a one to many relationship which is probably not what you want.
class User < ApplicationRecord
has_many :user_events
has_many :events, through: :user_events
end
class Event < ApplicationRecord
has_many :user_events
has_many :users, through: :user_events
end
# this is a join model.
class UserEvent < ApplicationRecord
belongs_to :user
belongs_to :event
end
A has_many :through association is often used to set up a many-to-many
connection with another model. This association indicates that the
declaring model can be matched with zero or more instances of another
model by proceeding through a third model.
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
You can generate the UserEvent model and the migration which creates the join table by running:
rails g model user_event user:belongs_to event:belongs_to
This will create a user_events table with the user_id and event_id foreign key columns. You should also roll back the migration which creates the users table and fix it:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password_digest # !!!
t.integer :code
t.timestamps
end
end
end
Note the addition of the password_digest column - this is required for has_secure_password. If you have already run this migration on the production database or committed and pushed it you should instead create separate migrations which fix the errors:
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column(:users, :password_digest, :string)
end
end
class RemoveEventFromUsers < ActiveRecord::Migration[5.0]
def change
remove_column(:users, :event)
end
end
To create an event which is associated with a user you can do:
event = user.events.new(name: "Dummy") # does not persist the record
event = user.events.create(name: "Dummy")
You can all assign records from either end by using the shovel operator:
user.events << event
event.users << user
Is this the right association for me?
My main goal for my application is to make it so a user has partys and
those parties have songs.
A party with only one user sounds pretty lame. However if you want to create a special relationship for the user you can create a separate association:
class User < ApplicationRecord
has_many :user_events
has_many :events, through: :user_events
has_many :owned_events, class_name: 'Event', foreign_key: 'owner_id'
end
class Event < ApplicationRecord
has_many :user_events
has_many :users, through: :user_events
belongs_to :owner, class_name: 'User'
end
class AddOwnerIdToEvents < ActiveRecord::Migration[5.0]
def change
add_column(:events, :owner_id, :integer)
add_foreign_key(:events, :users, column: :owner_id)
end
end
Another way to solve this is by adding a column to UserEvent join model which specifies what the association is. But this is pretty far beyond your skill level.
There is no foreign key in your tables. Supposing you are actually intending to have the models as explained ("event belongs to user"/"user has many events"), you need to add a column user_id to the events table, and not an event string to the users table.
You can create a migration or column definition with migration/model generators using the references type:
rails g model event name:string user:references
or
rails g migration add_user_id_to_event user:references
which will add column and the needed indexes.
Moreover, you have that a user has many events, so there is nothing like
user.event = Event.create
(there is no such method as User#event=) but instead
user.events << Event.create(...)
Related
I have the following associations set up:
class Book < ActiveRecord::Base
belongs_to :author
belongs_to :category
has_many :users_books
has_many :users, through: :user_books
end
and
class User < ActiveRecord::Base
has_many :users_books
has_many :books, through: :users_books
end
I created a join table migration as I ought to
class CreateUsersBooks < ActiveRecord::Migration[4.2]
def change
create_table :users_books do |t|
t.integer :user_id
t.integer :book_id
end
end
end
Now I need to create a method called check_out_book, that takes in a book and a due_date as arguments. When a user checks out a book, it should create a new UserBook record (or Checkout record or whatever you want to call you join table/model). That new UserBook record should have a attribute (and therefore table column) of returned? which should default to false. How would I go about creating this method and the migrations?
Your tablenames and your associations in Rails should always be singular_plural with the exception of the odd duckling "headless" join tables used by the (pretty useless) has_and_belongs_to_many association.
class CreateUserBooks < ActiveRecord::Migration[4.2]
def change
create_table :user_books do |t|
t.references :user
t.references :book
t.boolean :returned, default: false
end
end
end
class UserBook < ActiveRecord::Base
belongs_to :user
belongs_to :book
end
class Book < ActiveRecord::Base
belongs_to :author
belongs_to :category
has_many :user_books
has_many :users, through: :user_books
end
class User < ActiveRecord::Base
has_many :user_books
has_many :books, through: :user_books
end
But you should really use a better more descriptive name that tells other programmers what this represents in the domain and not just a amalgamation of the two models it joins such as Loan or Checkout.
I would also use t.datetime :returned_at to create a datetime column that can record when the book is actually returned instead of just a boolean.
If you want to create a join record with any additional data except the foreign keys you need to create it explicitly instead of implicitly (such as by user.books.create()).
#book_user = Book.find(params[:id]).book_users.create(user: user, returned: true)
# or
#book_user = current_user.book_users.create(book: user, returned: true)
# or
#book_user = BookUser.new(user: current_user, book: book, returned: true)
First I would like to know if there is any possibilities to associate one of my model with the ActiveAdmin::Comment and the AdminUser models
this is my model
class AdminAction < ActiveRecord::Base
has_one :comment, :class_name => "ActiveAdmin::Comment", :foreign_key => "admin_action_id"
belongs_to :admin_user
end
thoses associations don't raise any errors, just returning `nil``
I have added a field in thoses two models :
add_column :admin_users, :admin_action_id, :integer
add_column :active_admin_comments, :admin_action_id, :integer
The goal here is to fetch the AdminUser and the Comment associate to my new model AdminAction
and when I do
a = AdminAction
a.admin_user
# and
a.comment
it works
any ideas ?
You need to have a admin_user_id in the admin_actions table to make this belongs_to association work.
class AdminAction < ActiveRecord::Base
belongs_to :admin_user
end
Also, the foreign_key param is unneeded because it will be inferred from the AdminAction class name.
class AdminAction < ActiveRecord::Base
has_one :comment, :class_name => "ActiveAdmin::Comment", :foreign_key => "admin_action_id"
end
Other than that, what you have should work as expected. If it is not, please provide more detail as to what you are seeing, or not seeing as the case may be.
I have this working, albiet with a User model rather than AdminUser. Here is my code:
Migrations
class CreateAdminAction < ActiveRecord::Migration
def change
create_table :admin_actions do |t|
t.references :user, index: true
t.timestamps
end
end
end
class AddFieldsForAdminAction < ActiveRecord::Migration
def change
add_column :active_admin_comments, :admin_action_id, :integer
end
end
AdminAction class
class AdminAction < ActiveRecord::Base
has_one :comment, class_name: 'ActiveAdmin::Comment'
belongs_to :user
end
Another thought: if you are looking to get the ActiveAdmin::Comment records for a single AdminUser, I think you can fetch them directly like this:
admin_comments = ActiveAdmin::Comment.find_for_resource_in_namespace(AdminUser.find(some_id), :admin)
I've got a user table with all my users
Now I want to introduce user-groups
So I need a second table for the groups and a relation between those groups.
It should be possible to set a user in different groups. so I need a n:m relation
It read about that rails can generate most things I need and also generate the migration file? is that true? How does it works?
Migrations
class CreateUserGroups < ActiveRecord::Migration
def up
create_table :user_groups do |t|
t.string :name
t.integer :size
t.timestamps
end
end
def self.down
drop_table :user_groups
end
end
class CreateUserGroupUsers < ActiveRecord::Migration
def self.up
create_table :user_group_users do |t|
t.user_id:integer
t.user_groups_id:integer
t.timestamps
end
end
def self.down
drop_table :user_group_users
end
end
Create your User and UserGroup model and migration from terminal
rails g model User email:string password:string
rails g model UserGroup name:string size:integer
You'll also want to create a UserGroup and User relationship managing table called UserGroupManager
rails g model UserGroupManager user_id:integer user_group_id:integer
Update your database by running this command in terminal
rake db:migrate
Set up the relationships within app/models/
# app/models/user.rb
class User < ActiveRecord::Base
has_many :user_group_managers
has_many :user_groups, through: :user_group_managers
end
# app/models/user_group.rb
class UserGroup < ActiveRecord::Base
has_many :user_group_managers
has_many :users, through: :user_group_managers
end
# app/models/user_group_manager.rb
class UserGroupManager < ActiveRecord::Base
belongs_to :user_group
belongs_to :user
end
I'm really new to RoR so I apologize if I'm not thinking about this right. I have a Report where I need to be able to assign multiple users to that report. A user can be assigned to more than one report and a report can have multiple users. How do I create the database relationship where this would be allowed. I understand how to assign one user to one report but not many users to a single report.
I'd use a joining class to make this happen:
class Report
has_many :assignments
has_many :users :through => :assignments
end
class User
has_many :assignments
has_many :reports, :through => :assignments
end
class Assignment
belongs_to :report
belongs_to :user
end
The class Assignment has two fields: report_id and user_id to create the relationship.
Read the Ruby on Rails Guide to Active Record Associations: http://guides.rubyonrails.org/association_basics.html
I highly recommend you familiarize yourself with the Ruby on Rails guides. They will prove to be an invaluable asset!! For this task the site would be RailsGuides Active Record Associations.
As far as the code goes you want to create three database tables: reports, reports_users, and users, with reports_users being a join table.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class ReportsUsers < ActiveRecord::Migration
def change
create_table :reports_users, :id => false do |t|
t.references :user, :null => false
t.references :report, :null => false
end
end
end
Once you run this migration you need to set up the active record associations in your models.
class User < ActiveRecord::Base
has_and_belongs_to_many :reports
end
class Report < ActiveRecord::Base
has_and_belongs_to_many :user
end
This will set up the database and the many-to-many models connections. This will get you started. Now you have to go create some views
I have tree model Meeting , Client, Contact.
When i create new meeting, i can select client or contact , but how better store this structure and association? !Use case client_id and contact_id in meeting table not good.
We assume someone (a creator) can create a meeting. The creator may be a client or a contact.
For that you need a "creator_type" and "creator_id" column on your Meetings Table first, so add an migration using script/rails generate migration AddTypeToMeetings
Then edit the migration file like:
class AddTypeToMeetings < ActiveRecord::Migration
def self.up
add_column :meetings, :creator_id, :integer
add_column :meetings, :creator_type, :string
end
end
Second, you have to adapt your models:
meeting.rb
class Meeting < ActiveRecord::Base
# polymorphic association
belongs_to :creator, :polymorphic => true
end
client.rb
class Client < ActiveRecord::Base
has_many :meetings, :as => :creator
end
contact.rb
class Contact < ActiveRecord::Base
has_many :meetings, :as => :creator
end
How to use:
#my_meeting = Meeting.new
#my_meeting.creator = #my_client
# or if you want a contact:
#my_meeting.creator = #my_contact
You can read more up on polymorphic associations here:
ASCII Casts
Documentation (scroll to Polymorphic Association)