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 using the Non-Employee form (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 a nominee_username that exists in the Employee table, it should throw an error and direct them to the Employee form.
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 :employee_using_non_employee_form,
:on => :create, :unless => :employee_nomination?
def employee_nomination?
self.employee == true
end
def employee_using_non_employee_form
if nominee_username == employee.username ## -- this is where I'm getting errors. I get "undefined local variable or method employee for #<Award:.."
## I've also tried Employee.username, but get "undefined method username for #<Class..."
## Same error when I try nominee.username
errors.add(:nominator, "Please use Employee form.")
end
end
end
There is an association between the Award and Employee models, but I don't know how to call the Employee.username within the Award model to validate the Non-Employee form.
class Employee < ActiveRecord::Base
has_many :awards, :foreign_key => 'nominator_id'
has_many :awards, :foreign_key => 'nominee_id'
end
Try this for your validation method.
def employee_using_non_employee_form
if Employee.where(:username => nominee_username).present?
errors.add(:nominator, "Please use Employee form.")
end
end
Related
I have three models, Document, Section and Paragraph.
class Document < ActiveRecord::Base
attr_accessible :status
has_many :sections
accepts_nested_attributes_for :sections, :allow_destroy => :true
private
def assign_order_status
section_statuses = sections.map(&:status)
self.status =
if section_statuses.all? {|value| value == "completed" }
"completed"
elsif section_statuses.all? {|value| value == "new" }
"new"
else
"inprocess"
end
end
end
class Section < ActiveRecord::Base
attr_accessible :document_id, :status
belongs_to :document
has_many :paragraphs, :dependent => :destroy
accepts_nested_attributes_for :paragraphs, :allow_destroy => :true
private
def assign_order_status
paragraph_values = paragraphs.map(&:text)
self.status =
if paragraph_values.all? {|value| !value.nil? }
"completed"
elsif paragraph_values.any? {|value| !value.nil? }
"inprocess"
else
"new"
end
end
end
class Paragraph < ActiveRecord::Base
attr_accessible :section_id, :text
belongs_to :section
end
I want to update status of Document and Section models.
For example, 'status' column in sections table is depending on 'text' column in paragraphs table.
simillarly, 'status' column in documents table is depending on 'status' column in sections table.
Briefly, for sections,
If all the 'text' in paragraphs table is nil then the 'status' of corresponding section have to change as "new".
If any one 'text' column in paragraphs table is having value then the 'status' of section have to change as "inprocess".
Otherwise status is "completed".
for document,
If all the 'status' in section table is "new" then the 'status' of corressponding document have to change as "new".
If any one 'status' is "inprocess" then 'status' of document have to change as "inprocess".
Otherwise is "completed".
Problem:
I am confusing which callbacks is suitable for assign_order_status method.
Because 'status' of Document is depending on Section's status and Section's status is depending on value of Paragraph.
But Rails validation and callbacks are running from parent to child. In my case, calculation of 'status' value is based from child to parent.
How to update status value for both document and section before starting validation ?
Please anyone help me to solve this.
How can I get the data from an associated form and insert it to the associated table from the main model?
class Supplier < ActiveRecord::Base
has_one :account, foreign_key: "acc_sup_id", :autosave => true
self.primary_key = 'sup_id'
end
class Account < ActiveRecord::Base
belongs_to :supplier, foreign_key: "acc_sup_id"
self.primary_key = 'acc_id'
self.table_name = 'accounts'
end
I am having a combined form for Supplier and Account. When I submit I need to find a way to insert the corresponding values to Supplier and Account. The problem is Supplier values is inserting properly but not Account.
I have asked the same question in several forums, groups and even in stack but nobody seems to give a convincing answer.
The basic strategy is to first look at what params are being submitted when the form is submitted. You could add a line in the controller action such as raise params.inspect to see that. Make sure that those paras contain all the data you need; if not then there is some problem in the view that generates that form.
Once you have all the data getting to the controller action, then you need to change the controller action so that is properly interprets all the data and puts it into the correct models.
I cannot give any more specific advice unless you show the code for your view, the result from doing params.inspect, and the code for the controller action that takes the data.
Try this.
Let's assume that there are orders and customers tables and that you want to perform CRUD operations on customers from orders form.
Customer model is very simple
class Customer < ActiveRecord::Base
attr_accessible :name
end
Order model must provide virtual attributes for all customer's attributes (attr_accessor construct). CRUD for customers is provided through callbacks. Validations can be used as well.
class Order < ActiveRecord::Base
attr_accessor :customer_name
attr_accessible :description, :number, :customer_name
belongs_to :customer
validates_presence_of :number
validates_presence_of :description
validates_presence_of :customer_name
before_save :save_customer
after_find :find_customer
after_destroy :destroy_customer
protected
def save_customer
if self.customer
self.customer.name = self.customer_name
else
self.customer = Customer.create(name: self.customer_name)
end
self.customer.save
end
def find_customer
self.customer_name = self.customer.name
end
def destroy_customer
self.customer.destroy
end
end
Example grid for Order model.
class Orders < Netzke::Basepack::Grid
def configure(c)
super
c.model = 'Order'
c.items = [
:description,
:number,
:customer_name
]
c.enable_edit_inline = false
c.enable_add_inline = false
end
def preconfigure_record_window(c)
super
c.form_config.klass = OrderForm
end
end
Example form for Order model.
class OrderForm< Netzke::Basepack::Form
def configure(c)
super
c.model = 'Order'
c.items = [
:description,
:number,
:customer_name
]
end
end
I have three documents
class User
include Mongoid::Document
has_many :votos
...
...
end
class Picture
include Mongoid::Document
has_many :votos
belongs_to :user
...
...
end
class Voto
include Mongoid::Document
belongs_to :picture
belongs_to :user
field :value => :type => Integer
...
...
end
In the Voto document, the field value is a number between 1 and 5
So i need to get the most voted pictures of all to show...
How can i achieve this???
Thanks
You can do it by querying also but it will take hell of a time and performance will decrease. The other solution is create a field total_votos in model Picture and whenever a vote is given to a picture add the field value into total_votes
class Picture
include Mongoid::Document
has_many :votos
belongs_to :user
field :total_votes,:type => Integer
...
...
end
class Voto
include Mongoid::Document
belongs_to :picture
belongs_to :user
field :value => :type => Integer
after_create do
picture = self.picture
picture.total_votes += self.value
picture.save
end
...
...
end
and you can find the maximum value just by running the query
Picture.where(:max_votes => Picture.all.max(:total_votes))
I have a Fieldnote model in my app, which has_many :activities attached to it through a table called :fieldnote_activities. I then define a searchable index this way:
searchable :auto_index => true, :auto_remove => true do
integer :id
integer :user_id, :references => User
integer :activity_ids, :multiple => true do
activities.map(&:id)
end
text :observations
end
And then I have a Search model to store / update searches. The search model thus also has its own associations with activities. I then perform my searches like this:
#search = Search.find(params[:id])
#query = Fieldnote.search do |query|
query.keywords #search.terms
if #search.activities.map(&:id).empty? == false
query.with :activity_ids, #search.activities.map(&:id)
end
end
#fieldnotes = #query.results
Now this all works GREAT. The problem is that if I change which activities that are associated with a fieldnote, the search results do not change because it appears the indices for that fieldnote do not change. I was under the impression that the :auto_index => true and :auto_remove => true flags when I define the searchable index would keep track of new associations (or deleted associations), but this appears not to be the case. How do I fix this?
You're right that :auto_index and :auto_remove don't apply to associated objects, just the searchable object they are specified on.
When denormalizing, you should use after_save hooks on the associated objects to trigger a reindex where necessary. In this case, you want changes to the Activity model and the FieldnoteActivity join model to trigger a reindex of their associated Fieldnote objects when saved or destroyed.
class Fieldnote
has_many :fieldnote_activities
has_many :activities, :through => :fieldnote_activities
searchable do
# index denormalized data from activities
end
end
class FieldnoteActivity
has_many :fieldnotes
has_many :activities
after_save :reindex_fieldnotes
before_destroy :reindex_fieldnotes
def reindex_fieldnotes
Sunspot.index(fieldnotes)
end
end
class Activity
has_many :fieldnote_activities
has_many :fieldnotes, :through => :fieldnote_activities
after_save :reindex_fieldnotes
before_destroy :reindex_fieldnotes
def reindex_fieldnotes
Sunspot.index(fieldnotes)
end
end
Errors are added to error object of record but associations are still saved.
class Parent < ActiveRecord::Base
validate :valid_child?
#validation methods
protected
def valid_child?
#child_names = Hash.new
self.children.each do |curr_child|
if #child_names[curr_child.name].nil?
#child_names[curr_child.name] = curr_child.name
else
errors.add(:base, "child name should be unique for children associated to the parent")
end
end
end
#associations
has_and_belongs_to_many :children, :join_table => 'map__parents__children'
end
#query on rails console
#parent = Parent.find(1)
#parent.children_ids = [1, 2]
#parent.save
The problem is that, for an existing record, #parent.children_ids = [1, 2] will take effect a change in the database before the call to #parent.save.
Try using validates_associated to validate the children rather than rolling your own validation.
To make sure that the children's names are unique within the context of the parent, use validates_uniqueness_of with the :scope option to scope the uniqueness to the parent id. Something like:
class Child < ActiveRecord::Base
belongs_to :parent
validates_uniqueness_of :name, :scope => :parent
end