Hello I try to do a has_many through relation but it's not working as I expect.
Here are my models
def User < ApplicationRecord
has_many :user_roles, class_name: "UserRole"
has_many :roles, through: :user_roles
end
def Role < ApplicationRecord
has_many :user_roles, class_name: "UserRole"
has_many :users, through: :user_roles
end
def UserRole < ApplicationRecord
belongs_to :user
belongs_to :role
end
When I do this in rails console
User.roles
I've got the following error
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: relation "user_roles" does not exist)
I'm stuck with this error since 2 hours and no google result helped me ...
EDIT:
Here is my migration
class CreateUserRole < ActiveRecord::Migration
def change
create_table :user_role do |t|
t.belongs_to :user, type: :uuid
t.belongs_to :role, type: :uuid
end
end
end
Related
In my rails app I'm trying to create a system that will reward users with badges for various achievements
created a table 'user_badges'
migration:
class CreateUserBadges < ActiveRecord::Migration[5.1]
def change
create_table :user_badges do |t|
t.references :user, foreign_key: true
t.references :badge, foreign_key: true
t.timestamps
end
end
end
model UserBadge:
class UserBadge < ApplicationRecord
belongs_to :user
belongs_to :badge
end
модель Badge:
class Badge < ApplicationRecord
has_many :users, through: :user_badges
has_many :user_badges
end
model User:
class User < ApplicationRecord
...
has_many :badges, through: :user_badges
has_many :user_badges
...
end
when I try to add a badge to the user:
b = Badge.create(title: 'first')
User.last.badges << b
I get this error:
ActiveRecord::HasManyThroughOrderError: Cannot have a has_many
:through association 'User#badges' which goes through
'User#user_badges' before the through association is defined.
also when I simply call:
User.last.badges
same error:
ActiveRecord::HasManyThroughOrderError: Cannot have a has_many
:through association 'User#badges' which goes through
'User#user_badges' before the through association is defined.
Define has_many association first then add through: association
class UserBadge < ApplicationRecord
belongs_to :user
belongs_to :badge
end
class Badge < ApplicationRecord
has_many :user_badges # has_many association comes first
has_many :users, through: :user_badges #through association comes after
end
class User < ApplicationRecord
...
has_many :user_badges
has_many :badges, through: :user_badges
...
end
Note, in case you mistakenly wrote first has_many 2 times, then it can reproduce this error too. E.g.
class User < ApplicationRecord
...
has_many :user_badges
has_many :badges, through: :user_badges
...
has_many :user_badges
end
# => Leads to the error of ActiveRecord::HasManyThroughOrderError: Cannot have a has_many :through association 'User#badges' which goes through 'User#user_badges' before the through association is defined.
Active Record should alert has_many being used two times IMHO...
I have a has_and_belongs_to_many using has_many between users and workspaces.
user.rb
class User < ActiveRecord::Base
has_many :user_workspaces, dependent: :destroy
has_many :workspaces, through: :user_workspaces
before_destroy :delete_workspaces
def delete_workspaces
self.workspaces.each(&:destroy)
end
workspace.rb
class Workspace < ActiveRecord::Base
has_many :user_workspaces
has_many :users, through :user_workspaces
end
user_workspaces class and migration:
class UserWorkspace < ActiveRecord::Base
self.table_name = "user_workspaces"
belongs_to :user
belongs_to :workspace
end
class CreateUsersAndWorkspaces < ActiveRecord::Migration
def change
create_table :users_workspaces, id: false do |t|
t.belongs_to :user, index: true
t.belongs_to :workspace, index: true
t.boolean :admin, default: true
end
end
end
class RenameUsersWorkspaces < ActiveRecord::Migration
def change
rename_table('users_workspaces', 'user_workspaces')
end
end
I want this both test to pass:
should "destroy all associatios and objects" do
user = User.create!(attributes_for(:user))
w = user.workspaces.create!(attributes_for(:workspace))
user.destroy
assert UserWorkspace.all.empty? #asser there are no associations
end
which gives me the error
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column:
user_workspaces.: DELETE FROM "user_workspaces" WHERE
"user_workspaces"."" = ?
should "destroy association when destroying workspace" do
user = User.create!(attributes_for(:user))
w = user.workspaces.create!(attributes_for(:workspace))
w.destroy
assert UserWorkspace.all.empty?
end
How can I cover both scenarios? destroying an user destroys the association and the workspaces, destroying the workspace also destroys the association
According to http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html just need to ignore the join table.
Workspace.rb now has dependent destroy, to destroy only the join (intended behavior of destroy)
has_many :users, through: :user_workspaces,
inverse_of: :workspaces,
dependent: :destroy
then user.rb keeps the delete_workspaces functions, but adds dependent: :destroy, to also destroy the association.
user.rb
before_destroy: :delete_workspaces
has_many :workspaces, through: :user_workspaces,
dependent: :destroy
def delete_workspaces
self.workspaces.each(&:destroy)
end
now both test passes.
I have three Models: Deal, Zipcode, DealIncludeZipcode.
Now, the association looks like below:-
Deal Model:
class Deal < ActiveRecord::Base
has_many :deal_include_zipcodes, dependent: :destroy
has_and_belongs_to_many :zipcodes, dependent: :destroy
accepts_nested_attributes_for :deal_include_zipcodes,:reject_if => :reject_include_zipcodes, allow_destroy: true
private
def reject_include_zipcodes(attributes)
if attributes[:deal_id].blank? || attributes[:zipcode_id].blank?
if attributes[:id].present?
attributes.merge!({:_destroy => 1}) && false
else
true
end
end
end
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
class DealIncludeZipcode < ActiveRecord::Base
belongs_to :deal
belongs_to :zipcode
end
Now in view I have a checkbox,on unchecking it I can select multiple zipcode to select from DealIncludeZipcode.But when I save the data it is not saving.
I have used migration for joining Zipcode and Deal Model in which my exclude zipcode functionality is working correctly.
Please provide a soloution.I have tried various method but didn't got succeed.
The whole point of has_and_belongs_to_many is that you don't have a model which joins the two parts.
class Deal < ActiveRecord::Base
has_and_belongs_to_many :zipcodes
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
Would join through a "headless" table called deals_zipcodes. If you want to have a join model you need to use has_many :through instead.
class Deal < ActiveRecord::Base
has_many :deal_zipcodes, dependent: :destroy
has_many :zipcodes, through: :deal_zipcodes
end
class DealZipcode < ActiveRecord::Base
belongs_to :deal
belongs_to :zipcode
end
class Zipcode < ActiveRecord::Base
has_many :deal_zipcodes, dependent: :destroy
has_many :deals, through: :deal_zipcodes
end
I think Max's right. So your migration should be
create_table :deals do |t|
t.string :name
...
end
create_table :zipcodes do |t|
t.string :zipcode
...
end
create_table :deals_zipcodes do |t|
t.belongs_to :deal, index: true
t.belongs_to :zipcode, index: true
end
And your models should be
class Deal < ActiveRecord::Base
has_and_belongs_to_many :zipcodes
end
class Zipcode < ActiveRecord::Base
has_and_belongs_to_many :deals
end
You should probably take a look at the ActiveRecord guide, where you'll find more explanation.
I have a Users class, and a UserGroup class:
class User < ActiveRecord::Base
has_many :group_memberships
has_many :users_groups, through: :group_memberships
...
class UsersGroup < ActiveRecord::Base
has_many :group_memberships
has_many :users, through: :group_memberships
... and a GroupMembership class to join them -
class GroupMembership < ActiveRecord::Base
belongs_to :users, dependent: :destroy
belongs_to :users_groups, dependent: :destroy
My migrations look like this -
class CreateUsersGroups < ActiveRecord::Migration
def change
create_table :users_groups do |t|
t.string :title
t.string :status
t.string :about
t.timestamps null: false
end
end
end
class CreateGroupMembership < ActiveRecord::Migration
def change
create_table :group_memberships do |t|
t.integer :user_id, index: true
t.integer :users_group_id, index: true
t.boolean :owner
end
end
end
So user.group_memberships is perfectly happy, but user.users_groups returns an error -
undefined method `relation_delegate_class' for Users:Module
Similarly, users_group.group_memberships is fine, but users_group.users returns exactly the same error -
undefined method `relation_delegate_class' for Users:Module
... on the users module. I've stared at this for a couple of hours, but I'm sure it's simple syntax somewhere. What's the problem?
When using belongs_to I believe you need to use a singular format:
So not belongs_to :users but belongs_to :user
class GroupMembership < ActiveRecord::Base
belongs_to :user, dependent: :destroy
belongs_to :writers_group, dependent: :destroy
I believe that since you are using 'through' you will have to use:
user.group_memberships.users_groups
This is because users does not have users_groups or vice versa.
Instead you access the users_groups through group_memberships.
I have these 3 classes:
User:
class User < ActiveRecord::Base
end
UserStory:
class UserStory < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
belongs_to :assigned, class_name: 'User'
belongs_to :board
has_many :comments
has_many :watched_stories
has_many :watchers, through: :watched_stories, source: :user
end
WatchedStory:
class WatchedStory < ActiveRecord::Base
belongs_to :user
belongs_to :story, class_name: 'UserStory'
end
when I try to list all watchers via UserStory#watchers I see this error:
PG::UndefinedColumn: ERROR: column watched_stories.user_story_id does not exist
It seems like the relation has_many through is wrong, but I can see the error. What am I missing here?
My migration:
class CreateWatchedStories < ActiveRecord::Migration
def change
create_table :watched_stories do |t|
t.references :user, index: true
t.references :story, index: true, references: :user_story
t.timestamps
end
end
end
If WatchedStory and UserStory are connected through story_id you need to specify that, otherwise Rails will assume it's user_story_id:
class WatchedStory < ActiveRecord::Base
belongs_to :story, class_name: 'UserStory', foreign_key: :story_id
end
class UserStory < ActiveRecord::Base
has_many :watched_stories, foreign_key: :story_id
end
PG::UndefinedColumn: ERROR: column watched_stories.user_story_id does
not exist
Rails is looking for a column called user_story_id which didn't exist in your watched_stories table.
Reason
You have this line belongs_to :story, class_name: 'UserStory' in WatchedStory model,so with class_name specified as UserStory,Rails will look for user_story_id by default.
Fix
The error could be resolved by setting foreign_key option in your WatchedStory model
class WatchedStory < ActiveRecord::Base
belongs_to :user
belongs_to :story, class_name: 'UserStory',foreign_key: :story_id
end