act_as_list with intermediate table - ruby-on-rails

I'm trying to use act_as_list to order some items, but I'm having troubles with the scope, I want the scope to be the group of the item, but I have no idea how to do it. This is what I have now:
class Group < ActiveRecord::Base
has_many :types
has_many :items, through: :types
end
class Type < ActiveRecord::Base
belongs_to :group
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :type
acts_as_list scope: ?
end
I tried with scope: [type: :group] but it doesn't work, I tried with:
has_one :group, through: :type
and
def group_id
type.group.id
end
But then I got an error with PG because the column group_id doesn't exists...
Any idea?

Related

Uniqueness field using Scope of association

I want to insure that an items name is unique within an organization. So I've used the "validates_uniqueness_of :name, scope: [:organization]" within Item. This unfortunetely didn't work.
Error (edited):
> 1) Item
> Failure/Error: #item_1 = create(:item, :item_category => #item_cat_1)
>
> NoMethodError:
> undefined method `organization_id' for #<Item:0x00000002565840>
models:
class Item < ActiveRecord::Base
belongs_to :item_category
has_one :organization, through: :item_category
validates_uniqueness_of :name, scope: [:organization]
end
class ItemCategory < ActiveRecord::Base
has_many :items
belongs_to :organization
end
class Organization < ActiveRecord::Base
has_many :item_categories
has_many :items, :through => item_categories
end
In theory, as I did above may I use the item's, item_category association (belongs_to :item_category) for the organization_id?
If the above isn't possible. I guess I could have an organization_id in the item and the item_category. But then how could we validate that a item.organization_id be always equal to an item_category.organization_id (its association)
It is okay to not include the organization_id inside an item?
Yes, not include because the column organization_id will be redundant.
For complex validation, we usually use customized one to validate, here is my example, you may correct it:
class Item < ActiveRecord::Base
belongs_to :item_category
has_one :organization, through: :item_category
# validates_uniqueness_of :name, scope: [:organization]
validate :check_uniqueness_of_name
def check_uniqueness_of_name
if Organization.includes(item_categories: :items).where.not(items: {id: self.id}).where(items: {name: self.name}).count > 0
errors.add(:name, 'name was duplidated')
end
end
end

Rails has_many through: (many to many relationship) error uninitialized constant Group::Keywords

A Group can have many keywords and a Keyword can have many groups. I have this relationship defined as
class Keyword < ActiveRecord::Base
has_many :groups_keywords
has_many :groups, through: :groups_keywords
end
class GroupsKeyword < ActiveRecord::Base
belongs_to :groups
belongs_to :keywords
end
class Group < ActiveRecord::Base
has_many :groups_keywords
has_many :keywords, through: :groups_keywords
end
I can do Group.find(1).groups_keywords so the relationship is working?
But I want to get all of my Groups keywords so I do the following.
Group.find(1).keywords
But I get the error uninitialized constant Group::Keywords
Try changing the below
class GroupsKeyword < ActiveRecord::Base
belongs_to :groups
belongs_to :keywords
end
to
class GroupsKeyword < ActiveRecord::Base
belongs_to :group
belongs_to :keyword
end

Rails: three-way has_many/through relationship: prevent duplicate join items creation

Here is an extract of the models I have:
class User < ActiveRecord::Base
has_many :participations
has_many :groups, through: :participations
has_many :subgroups, through: :participations
end
class Group < ActiveRecord::Base
has_many :participations
has_many :users, through: :participations
has_many :subgroups
end
class Subgroup < ActiveRecord::Base
has_many :participations
has_many :users, through: :participations
end
class Participation < ActiveRecord::Base
belongs_to: :user
belongs_to: :group
belongs_to: :subgroup
validates :user, presence: true
validates :group, presence: true
# Subgroup can be empty, as long as user as not been placed.
# There should be only one participation per couple User:Group
validates_uniqueness_of :group_id, :scope => [:user_id]
# Also has a state-machine, describing the participation status.
end
Explanation: groups are split in subgroups, users select the group they join, but not the subgroup, which is selected later by an administrator.
When a User is added to a Group (group_a.users << user_a), a Participation is automatically created by ActiveRecord.
I would like the same participation to be reused when the same User is added to a Subgroup of that Group (subgroup_1.users << user_a with subgroup_1 a Subgroup of group_a's).
What happens actually is ActiveRecord trying to create a new Participation record, which conflicts with the previously created one (validates_uniqueness_of :group_id, :scope => [:user_id]
fires an error).
Is there anyway I could make this work? I tried hooking before_validation, before_save, and some other stuff, but every attempt failed.
Maybe there is a better way to actually model this relationship?
Any help is welcome.
Thank you,
David
You could DRY up all of your code by instead calling
class User < ActiveRecord::Base
has_many :participations
has_many :groups, through: :participations
has_many :subgroups, through: :groups # HMT -> HMT
end
Would this solve your problem? This probably won't scale, but we'll worry about that later :).

How to get related records across a join table in Rails?

In my Rails application I have people which can have many projects and vice versa:
# app/models/person.rb
class Person < ActiveRecord::Base
has_many :people_projects
has_many :projects, :through => :people_projects
end
# app/models/people_project.rb
class PeopleProject < ActiveRecord::Base
belongs_to :person
belongs_to :project
end
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :people_projects
has_many :people, :through => :people_projects
def self.search(person_id)
if person_id
where("person_id = ?", person_id) # not working because no person_id column in projects table
else
scoped
end
end
end
How can I filter the projects by person_id in the index view of my ProjectsController, e.g. by using a URL like this: http://localhost:3000/projects?person_id=164
I can't get my head around this. Please help! Thanks...
Your association definition is not complete for Person and Project models. You also need has_many :people_projects defined.
# app/models/person.rb
class Person < ActiveRecord::Base
has_many :people_projects # <-- This line
has_many :projects, :through => :people_projects
end
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :people_projects # <-- This line
has_many :people, :through => :people_projects
end
# app/models/people_project.rb
# This is defined correctly
class PeopleProject < ActiveRecord::Base
belongs_to :person
belongs_to :project
end
Please reference The has_many :through Association for further details.
With this definition, you will be able to get all the projects of the current user using current_user.projects, just like you've already done in your ProjectsController#index.
Update:
You could use either joins or includes in your search method and apply the where condition. Something like follows:
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :people_projects
has_many :people, :through => :people_projects
def self.search(person_id)
if person_id
includes([:people_projects, :people]).where("people.id = ?", person_id)
else
scoped
end
end
end
You will not have a person_id in the projects table because its a has_many<>has_many relationship.
Simply #person.projects will perform a join btw person_projects & projects tables and returns the appropriate projects.
*I assume,current_user returns a Person object.*
Also, complete your Model definitions. Each of them should list their relation to PeopleProjects
class Person < ActiveRecord::Base
has_many :people_projects
has_many :projects, :through => :people_projects
end
class Project < ActiveRecord::Base
has_many :people_projects
has_many :people, :through => :people_projects
end

Rails - how to find out user's role in the system?

I have following models:
class Role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class User < ActiveRecord::Base
has_many :assignments
has_many :roles, :through => :assignments
...
end
I am trying to find out user's role, but when I try to
user.assignments.name
It doesn't print out the user's role from the table roles (column name).
How to print out that?
You need to map on your association in order to get a specific field:
user.roles.map(&:name)
Try this.
user.roles.each {|role| puts role }
You can't call name method on user.assignments because it's an array.
user.assignments.each do |a|
puts a.name
end

Resources