Configuring Categorizations With Rails 3 - ruby

I want to be able to assign categories to my user's (up to 2, allow for 1). I want any posts by this user to be assigned only one category from the same list of categories (which are referred to as profession(s) for my app).
Currently, I have configured it so that I can assign 1 to each, with simple belongs_to and has_many associations between the user, post, and profession models. This works fine for the post, because it only requires 1 profession assignment, but for the user it is limiting the ability for 2.
The view for the user has two drop-down lists, populated by the items in the profession. I can select two different professions, but only one retains the value for the profession, where I would like it to keep both or only accept one if only one has been selected. My major limitation is that in the user database, there is only one profession column that refers to the profession_id. I can't duplicate the profession column, so how do I set it up so that a second profession field can be added?
Or, how should I change my database design and models to accomplish this?
user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email,
:password,
:password_confirmation,
:remember_me,
:first_name,
:last_name,
:profile_name,
:full_bio,
:mini_bio,
:current_password,
:photo,
:profession_id
attr_accessor :current_password
validates :first_name, :last_name, :profile_name, presence: true
validates :profile_name, uniqueness: true,
format: {
with: /^[a-zA-Z0-9_-]+$/
}
has_many :posts
belongs_to :profession
has_attached_file :photo,
:default_url => 'default.png'
def full_name
first_name + " " + last_name
end
end
post.rb:
class Post < ActiveRecord::Base
attr_accessible :content, :name, :user_id, :profession_id
belongs_to :user
belongs_to :profession
validates :content, presence: true,
length: { minimum: 2 }
validates :name, presence: true,
length: { minimum: 2 }
validates :user_id, presence: true
end
profession.rb:
class Profession < ActiveRecord::Base
attr_accessible :name
has_many :posts
has_many :users
end

In this case, a has_many :through association for your Users and Professions may work best. With an additional model of something like "Specialty", you can model this relationship as follows:
class User < ActiveRecord::Base
has_many :specialties
has_many :professions, :through => :specialties
end
class Profession < ActiveRecord::Base
has_many :specialties
has_many :users, :through => :specialties
end
class Specialty < ActiveRecord::Base
belongs_to :user
belongs_to :profession
end
You can then use the nested_form gem in your view to accept the professions associated with that user.

Related

Validate uniqueness nested model params

I have three models:
class User < ActiveRecord::Base
has_many :user_countries
accepts_nested_attributes_for :user_countries, reject_if: :all_blank
validate :user_countries
end
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
end
class Country < ActiveRecord::Base
has_many :user_countries
has_many :users, :through => :user_countries
end
In a the user creation form I can create user_countries too. How I can validate in server the uniqueness of country_id in user_countries. A user has many countries: France, United State... but not for example: France and France.
I've added this to user_countries.. but it don't work:
validates :user_id, uniqueness: {scope: :country_id, allow_blank: false}
Try this in the user_country model.
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
validates_uniqueness_of :user_id, scope: :country_id, allow_blank: false
end
Also, you need to create a migration like below to add unique indexes on database level.
add_index :user_countries, [ :user_id, :country_id ], :unique => true

How can two user instances have the same account

In my rails app I want to create a shared account (later with different access levels). I want two instances of the User to have the same account.
My User Model has_many :accounts and my Account belongs_to :user
In the rails console when I do, e.g:
account = Account.first
account.user_id = [1, 2]
account.save
it returns true but when I check it again account.user_id = nil
How should I go on about it, then?
EDIT:
The Account Model:
class Account < ActiveRecord::Base
belongs_to :user
has_many :products
validates_presence_of :title
end
and the User model:
class User < ActiveRecord::Base
has_many :accounts
has_many :products, through: :accounts
accepts_nested_attributes_for :accounts
validates_presence_of :name
before_save do
self.email = email.downcase unless :guest?
end
validates :name, presence: true, length: { maximum: 50 }, unless: :guest?
end
EDIT 2:
I've updated the models relationship so the new Account model is:
class Account < ActiveRecord::Base
has_and_belongs_to_many :users
validates_presence_of :title
end
and the new User model is:
class User < ActiveRecord::Base
has_and_belongs_to_many :accounts
belongs_to :account
has_many :products, through: :accounts
accepts_nested_attributes_for :accounts
validates_presence_of :name
before_save do
self.email = email.downcase unless :guest?
end
validates :name, presence: true, length: { maximum: 50 }, unless: :guest?
end
I also created a new migration, a accounts_users table
class CreateAccountsUsersJoinTable < ActiveRecord::Migration
def change
create_join_table :users, :accounts do |t|
## Not sure if this is necessary
##t.index [:user_id, :account_id]
##t.index [:account_id, :user_id]
t.belongs_to :user
t.belongs_to :account
end
end
end
Still I can't have a account with multiple users

Mongoid: Referencing Same Model More Than Once Through has_many

I'd like to be able to reference a model (a has_many relationship) more than once in the same model. For example, given the following models:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
has_many :secondary_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :effortable, polymorphic: true
validates_presence_of :name
end
As you can see, the Effort model is referenced twice. Originally, my Effort model wasn't polymorphic, but it seemed Mongoid was unable to determine which collection (main_efforts or secondary_efforts) the effort belonged to. As such, I made it polymorphic. After making it polymorphic, however, my main_efforts and secondary_efforts fields are always an empty array.
What is the proper way to reference a polymorphic model more than once in the same model (assuming a polymorphic model is necessary)?
Figured it out:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :main_effort
has_many :secondary_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :secondary_effort
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :main_effort, :class_name => 'Conop', :inverse_of => :main_efforts
belongs_to :secondary_effort, :class_name => 'Conop', :inverse_of => :secondary_efforts
validates_presence_of :name
end

Mongoid not saving nested_attributes for 'belongs_to' in a 1:1 relationship

I have two model's Contact, and User. When I create a new user I am trying to create the contact at the same time. But It is not getting created for some reason. Any ideas on why?
class Contact
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
include Mongoid::Paranoia
include Mongoid::Versioning
# Attr.
attr_accessible :first_name, :last_name, :birthday, :email_addresses_attributes, :phone_numbers_attributes, :relationships_attributes, :addresses_attributes
#Relationships
belongs_to :firm, validate: true
has_one :user # contact information for user
has_many :relationships, autosave: true
has_many :clients
has_many :notes, dependent: :destroy
...
end
class User
include Mongoid::Document
include ActiveModel::SecurePassword
include Mongoid::Timestamps
# Attr.
attr_accessible :contact_id, :contact_attributes, :password, :password_confirmation, :google_tokens
#Relationships
belongs_to :firm, validate: true
belongs_to :contact, validate: true, autosave: true
has_one :user_type
embeds_many :histories
# Nested Attrs
accepts_nested_attributes_for :contact
...
end
accepts_nested_attributes_for is done on the owner object to allow you to set attributes of objects that belong it.
In your case, User belongs to (or is nested under) Contact. You would have to do accepts_nested_attributes_for :user in your Contact model.
You could switch it around so that User has_one :contact and Contact belongs_to :user. This requires you give Contact a user_id field.

has_many :through child and parent validations

I have a rails 3.0
has_many :X, :through => :something set up and i have a custom validator that does some custom validation on some complicated logic. I want to when you add anything to this many to many relationship both models are valid?
Project Class:
class Project < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
validates :name, :presence => true
end
Assignment:
class Assignment < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
User class with custom validator:
class MyCustomValidator < ActiveModel::Validator
def validate( record )
if record.projects.length > 3
record.errors[:over_worked] = "you have to many projects!"
end
end
end
class User < ActiveRecord::Base
has_many :assignments
has_many :projects, :through => :assignments
validates :name, :presence => true
validates_with MyCustomValidator
end
What i really want to do is prevent each model from invalidating the other so to say
prevent
my_user.projects << fourth_project
and
my_project.users << user_with_four_projects_already
from happening. Right now it allows the assignment and just the user becomes invalid.
class Project < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
validates :name, :presence => true
validates_associated :users
end
According to the docs, users must already be assigned to Projects in order to be validated. So:
my_user.projects << fourth_project
would occur, then projects would validate the user and see that it is indeed invalid, making the project invalid as well as in the inverse example.

Resources