Alarm verification errors when assigning a virtual attribute?

This is a question with Rails / ActiveRecord.

I have a model that basically should represent events or performances. Each event has many attributes: the attribution is basically something like "In this case, Person X has the Y role."

I came to the conclusion that the best way to allow the user to edit this data is to provide a free text field that expects a structured format, which I will call a role string:

singer: Elvis Costello, songwriter: Paul McCartney, ...

where I use autocompletion to perform both role names (singer, songwriter ...) and people names. Both roles and people are stored in a database.

To implement this, I created a virtual attribute in the Event model:

 def role_string # assemble a role string from the associations in the model end def role_string=(s) # parse a string in the above role string format, # look up the People and Events mentioned, and update # what in the database end 

Everything is fine. All this works very well when the role string is well formed and the associations defined by the role string are checked.

But what if the role string is incorrect? Well, I suppose I can just use regex along with standard validation to validate the format:

 validates_format_of :role_string, :with => /(\w+:\s*\w+)(,\s*\w+:\s*\w+)*/ 

But what if the associations implied by the role string are not valid? For example, what happens if I give the above line of the role and Elvis Costello does not refer to a real person?

I thought that I could use validates_each for the :role_string attribute to search for associations and throw an error if one of the names it names does not match, for example.

My questions are two: firstly, I do not like this approach, because to check the associations I will have to parse the string and look for them, which duplicates what I will do in role_string= , except for actually storing the associations in the database.

Secondly ... how would I indicate that an error occurred while assigning this virtual attribute?

+3
source share
1 answer

First of all, you are wrong with the person to the event. Instead, you should pass the Person identifier for the event, not the person’s name string. For example, what if Person ID 230404 and the name Elvis Costello changes its name to Britney Spears? Well, if that happens, the identifier will remain the same, but the name will change. However, you will no longer be able to refer to this person.

You need to set up your associations so that the foreign key refers to people in several cases:

 has_one :singer, :class_name => "Person", :foreign_key => "singer_id" has_one :songwriter, :class_name => "Person", :foreign_key => "songwriter_id" 

Thus, you can have several people associated with the event under different roles, and you can refer to several attributes that a person may have. For instance:

 Event.first.singer.name # => "Elvis Costello" Event.first.songwriter.name # => "Britney Spears" 

You can examine the available validations for associations ( validates_associated ), as well as whether an ID is present on the form ( validates_presence_of ). I would recommend creating your own check to make sure that the Person is valid before creation. Something like (unverified):

 def before_save unless Person.exists?(self.songwriter_id) self.errors.add_to_base("Invalid songwriter. Please try again!") return false end end 

In addition, I noticed that you are looking for a way for users to choose the user to be used for roles in your Event. Here is what you can do in your form:

 select(:event, :singer_id, Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => 'None' }) 

Hope this helps!

+3
source

All Articles