Rails 3.2 - Validate in Model Based on Another Model - ruby-on-rails-3

I have an AWARD model - there are two forms to create an AWARD. One is for nominating EMPLOYEES, the other is for Non-Employees. The EMPLOYEE form pulls a list of active employees to populate the Nominee selection box. The Non-Employee form has only text fields to populate the Nominee field (because I have no source to populate a selection list).
To dummy-proof the app, I want to run a validation that disallows Employees from nominating themselves (because they will inevitably try to do so!). There is a hidden field on each form to set whether the form is Employee or Non: <%= f.hidden_field :employee, :value => true/false %>
So, on the Non-Employee form, if the user types in his own nominee_username, it should throw an error that says he cannot nominate himself.
I have a validation, but the error throws even if the nominee_username DOES NOT match the nominator. So, there is a problem with my validation.
Here's what I've attempted:
class Award < ActiveRecord::Base
belongs_to :nominator, :class_name => 'Employee', :foreign_key => 'nominator_id'
belongs_to :nominee, :class_name => 'Employee', :foreign_key => 'nominee_id'
validate :cant_nominate_self_non_employee_form,
:on => :create, :unless => :employee_nomination?
def employee_nomination?
self.employee == true
end
##### the validation below is not working properly - it throws error every time ####
##### only if Employee.username is equal to award.nominee_username, it should error ####
def cant_nominate_self_non_employee_form
if Employee.where(:username => nominee_username)
errors.add(:nominator, "can't nominate yourself")
end
end
end
There is an association between the Award and Employee models:
class Employee < ActiveRecord::Base
has_many :awards, :foreign_key => 'nominator_id'
has_many :awards, :foreign_key => 'nominee_id'
end

Related

Rails 3.2 Validate based on different model

How would I make this work? I want to validate an award nomination based on criteria from a different model.
class Award < ActiveRecord::Base
belongs_to :manager, :class_name => 'Manager', :foreign_key => 'manager_username'
def cant_be_manager
if nominee_username == Manager.username
errors.add(:nominee, "is a manager and cannot be nominated.")
end
end
end
Try this:
class Award < ActiveRecord::Base
belongs_to :manager, :class_name => 'Employee', :foreign_key => 'manager_username'
validate :cant_be_manager # <----- added this line
def cant_be_manager
if nominee_username == manager.username # <----- lower case m
errors.add(:nominee, "is a manager and cannot be nominated.")
end
end
end
But (just guessing here what your model looks like) I'm wondering if that second modified line shouldn't be:
if nominee_username == manager_username
The belongs_to line indicates that you have a manager_username field in your awards table, but it would be more common in Rails for this to be a manager_id field, with the belongs_to line looking like this:
belongs_to :manager, :class_name => 'Employee', :foreign_key => 'manager_id'
If that is indeed what you have, your code should look like this:
class Award < ActiveRecord::Base
belongs_to :manager, :class_name => 'Employee', :foreign_key => 'manager_id' # <----- changed
validate :cant_be_manager # <----- added this line
def cant_be_manager
if nominee_id == manager_id # <----- changed
errors.add(:nominee, "is a manager and cannot be nominated.")
end
end
end
This assumes that you are trying to prevent an employee from nominating his own manager, but it's okay for the employee to nominate other managers, or for managers to nominate other managers. If instead you want to prevent any managers at all from being nominated by anyone, let me know how you know if an Employee is a manager (probably an attribute or method on your Employee model) and I will update the answer.
Maybe smth. like this?
class Award < ActiveRecord::Base
validate :cant_be_manager
def cant_be_manager
.....
end
See this question too: Rails custom validation

activeadmin habtm better example for uniqueness case

Am able to manage habtm as per follow, and I wanted a better way for this
I have habtm between User and Tag on Rails 3, aa 0.5.1
Tag name is uniq
f.input :tags, :label => 'Assign existing tag'
# this above allows to select from existing tags, but cannot allow to create one
f.has_many :tags, :label => 'Add new tags, modify existings' do |ff|
ff.input :name
ff.input :_destroy, :as => :boolean
end
# this above allows to create new one but not allow to specify existing one
# if we specify existing one, uniqueness wont let create this one, neither existing get used
# and throws validation error
any hints?
Adding my models
class User < ActiveRecord::Base
has_and_belongs_to_many :tags
scope :tagged_with, lambda {|tags| joins(:tags).where("tags.name" => tags)}
accepts_nested_attributes_for :tags, :allow_destroy => true
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :users
validates :name, :uniqueness => { :case_sensitive => false }
end
Try this,
f.label => 'Assign existing tag'
f.select :tags, Tag.all.map{|t| [t.tag_name, t.id]}, {:prompt => "Select Tag name" }
this above allows to select from existing tags, don't have option to create one
For the Second thing add this line in the model,
validates :tags, :uniqueness => {:scope => :tag_name}
here the :tag_name is your name of the fieldname. This throw an error if the tag name already exists when you create a duplicate.
It's just an idea as per your question. This won't be your exact answer because your specification is not enough to give you the exact answer.

Rails Pass A Parameter To Conditional Validation

I'm importing heaps of student data from an spreadsheet document. Each row of student data will represent a new user, however, the possibility of importing an already existing student exists and I want to bypass some of my user validations such as username uniqueness accordingly so that I can build associations for both new and existing records, but only if they're being imported to the same school.
Thus far I have the following validation setup in my User model:
user.rb
validates_uniqueness_of :username, :unless => :not_unique_to_school?
def not_unique_to_school?
user = find_by_username(self.username)
user.present? && user.school_id == 6
end
Now how would I go about replacing that 6 with a value I have access to in the controller? Instructors will be the ones handling the importing and they'll be importing students to their school so I would typically run current_user.school_id to retrieve the school id that I want them to be imported to, but I don't have access to the current_user helper in my model.
I'm not concerned about duplicating usernames as I'll be handling that on a different step, this is just the preliminary validation.
Edit
Simplified school & user model:
user.rb
class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username,
:first_name, :last_name, :school_id, :roles_mask
belongs_to :school
validates_presence_of :username, :on => :create, :message => "can't be blank"
validates_uniqueness_of :username, :unless => :unique_to_school?
def unique_to_school?
user = find_by_username(self.username)
user.present? && user.school_id == 6
end
def find_by_username(username)
User.where(:username => username).first
end
end
school.rb
class School < ActiveRecord::Base
attr_accessible :country_id, :name, :state_id
has_many :users
end
I'd add a method to your School model:
def student_named?(name)
self.users.where(:username => name).any?
end
then in your validation:
def not_unique_to_school?
self.school.student_named?(self.username)
end
Here's what ended up working for me:
validate :user_cant_be_duplicate_in_other_schools
def user_cant_be_duplicate_in_other_schools
errors.add(:username, :taken) if User.count(:conditions => ["school_id != ? AND username = ?", self.school_id, self.username]) > 0
end
As opposed to testing if a User belongs to a particular school we're testing for the lack of belonging to a particular school. I didn't come up with this answer, another user posted this as an answer but deleted it shortly after for reasons unknown.

cant setup an active admin resource form with has many :through assoc

I'm working on a rails (3.7.8) app and using active admin to manage resources for the ff models:
class AdminUser < ActiveRecord::Base
has_many :user_article_categories, :include => :article_categories
has_many :article_categories, :through => :user_article_categories,
:source => :admin_user
has_many :articles, :through => :user_article_categories,
:source => :admin_user
# ...
end
class UserArticleCategory < ActiveRecord::Base
belongs_to :admin_user
belongs_to :article_category
attr_accessible :admin_user_id, :article_category_id, :included
attr_accessor :included
after_find :set_included
private
def set_included
self.included = "1"
end
# ...
end
the "included" attribute was based on a solution presented here
class ArticleCategory < ActiveRecord::Base
has_many :user_article_categories, :include => :admin_users
has_many :admin_users, :through => :user_article_categories,
:source => :article_category
has_many :articles, :through => :user_article_categories,
:source => :article_category
# ...
end
but I seem not to get setting up (correctly) a form for admin_users, such that creating a new admin_user would have all article_categories displayed as a list of checkboxes
while a persisted admin_user for update would have all article_categories checkboxes displayed but wit all previously set article-categories checked, so that an update would remove unchecked checkboxes and add newly checked ones to what goes to the join-table
for admin/admin_users.rb I create the form as follows, this does not work, though it renders correctly, any help will be appreciated
form do |f|
if f.object.persisted? and current_admin_user.id == f.object.id
f.inputs "Admin Details" do
f.input :email
f.inputs :for => user_article_categories do |usr_art_catr|
usr_art_catr.input :article_category_id, :hidden
usr_art_catr.input :included
end
end
else
f.inputs "Admin Details" do
f.input :email
f.input :superuser, :label => "Super User Priveleges"
f.input :article_categories, :as => :check_boxes,
:collection => ArticleCategory.select("id, name")
end
end
f.buttons
end
Actually, to display a list of checkboxes of all article_categories and check all already checked article categories for a given admin_user on update.
Formtastic, when rendering the show form for the form's object, calls a method provided on the form object via
f.input :method_to_be_called, :as => :checkboxes
which formtastic would compare its result with a collection provided via
the
:collection => any_valid_ruby_object
but both should return the same kinds; array/array or hash/hash, whatever, to determine which checkboxes should be checked, by performing a difference on the two collections.
The method called by formtastic could be an instance method on admin_user that queries the join-table, to determine which checkboxes should be checked and builds an array of that from the related article_categories table or returns an empty array when there is none.
This allows formtastic do what is right, as least in this context. This solution makes the "included" attribute on user_article_categories (the join-table) redundant!

Rails: validation fail for a nested model on key field presence check

I have a model User and a nested model Mobility
class User < ActiveRecord::Base
has_many :mobilities, :dependent => :destroy
accepts_nested_attributes_for :mobilities
end
and
class Mobility < ActiveRecord::Base
belongs_to :mobile_user, :class_name => 'User'
validates :city_id, :presence =>true
validates :user_id, :presence =>true
validates :city_id, :uniqueness => {:scope => [:user_id]}
end
my view
=form_for #user, :as => :user, :html =>{ :class => 'form-horizontal'} do |f|
=f.fields_for :mobilities do |city_form|
=city_form.text_field :city_id, :id => "city_id_#{index}"
= f.submit "Retour"
my problem is that when I submit the form Rails render me this validation error:
Mobilities user > doit ĂȘtre rempli(e)
But if a I comment this line:
#validates :user_id, :presence =>true
Both, my Mobility and User objects get saved and know what: user_id field of #mobility is OK (indicatie my #user's ID)
If I send the form with 2 identical mobility inside, both model get saved but it seems my validation of uniqueness didn't check nothing because i have 2 Mobility object with same user_id and city_id in my database...
In fact it seems like my validation can't read my user_id 's key when validating.
I understand that because my User model did'nt get saved yet and doesnt have any ID yet... but that is my question:
How can i check both: presence of user_id and uniqueness with scope ???