2010-02-08 12 views
0

Je rencontre des problèmes avec les validations personnalisées de mes rails.Validations personnalisées Rails avec formulaires multi-modèles

def validates_hsp_program(*attr_names) 
    options = attr_names.extract_options! 
    regex = '^(' 
    err = '' 
    $CetConfig.program.each do |key, val| 
     regex << val.to_s << '|' 
     err << $CetConfig.program_prefix + " " + val.to_s + ", " 
    end 

    regex.chomp!('|') 
    regex << ')$' 
    regex = Regexp.new(regex) 

    validates_each attr_names do | record, attr_name, value | 
    exit 1 
     unless value.nil? or value =~ regex 
     record.errors.add(attr_name, 'must be one of ' + err.chomp(", ")); 
     end 
    end 

    end 

Le problème est que pour des fins de débogage j'ai ajouté la sortie 1 alors que je ne reçois pas le message d'erreur pour date non valide pour ce champ. Cependant, il ne sort jamais. C'est la même chose que dans tous mes autres validateurs personnalisés. La seule différence que je peux voir est que celui-ci est le deuxième modèle d'une forme multi-modèle et tous les autres sont sur le premier modèle ... Qu'est-ce que je fais mal?

Mon modèle

class ProfileProgram < ActiveRecord::Base 
    set_table_name "profile_program" 
    set_primary_key "STUDENT_ID" 
    belongs_to :profile_core, :primary_key => "STUDENT_ID", :foreign_key => "STUDENT_ID" 

    validates_presence_of :program 
    validates_hsp_program :program 
end 

action de mon contrôleur

def create 
    @pc = ProfileCore.new(params[:profile_core]) 
    @pp = ProfileProgram.new(params[:profile_program]) 

    @pc.student_type = $CetConfig.student_type.application 
    @pc.AGENT_ID = current_agents_staff.AGENT_ID 

    year = @pc.contract.to_s 

    case @pp.program 
    when 10 then 
     sd = year + '-09-01' 
     ed = year + '-06-30' 
    when 51 then 
     sd = year + '-08-15' 
     ed = year + '-06-30' 
    when 52 then 
     sd = year + '-01-15' 
     ed = year + '-06-30' 
    when 12 then 
     sd = year + '-01-15' 
     ed = year + '-01-14' 
    else 
     sd = nil 
     ed = nil 
    end 

    @pc.start_date = Date.parse(sd) unless sd.nil? 
    @pc.end_date = Date.parse(ed) unless ed.nil? 

    @pc.program_status = $CetConfig.student_status.apply 

    if @pc.valid? and @pp.valid? 
    ProfileCore.transaction do 
     @pc.save! 
     @pp.save! 
    end 
    redirect_to(students_path(@pc.STUDENT_ID)) 
    else 
    render :action => 'new' 
    end 
end 

Mon point de vue (element_block est une aide qui vient enfourne l'étiquette et sur le terrain dans les bonnes balises pour le dl)

<% form_for :profile_core, @pc, :url => { :controller => 'core', :action => 'create'} do |f| %> 
    <%= error_messages_for :object => [ @pc, @pp ] %> 
    <dl> 
    <%= element_block f.label(:contract, 'Contract Year'), f.contract_year_select(:contract) %> 
    <% fields_for :profile_program do |pp| %> 
     <%= element_block pp.label(:program, 'Program'), pp.hsp_program_select(:program) %> 
    <% end %> 

    <%= element_block f.label(:passport_number, 'Passport Number'), f.text_field(:passport_number) %> 
    <%= element_block f.label(:passport_country, "Country that issued the student's passport"), f.countries_select(:passport_country) %> 
    <%= element_block f.label(:passport_expires, 'Passport Expiration Date'), f.text_field(:passport_expires, :class => 'datepicker') %> 
    <%= element_block f.label(:last_name, 'Last Name (as on passport)'), f.text_field(:last_name) %> 
    <%= element_block f.label(:first_name, 'First Name (as on passport)'), f.text_field(:first_name) %> 
    <%= element_block f.label(:middle_name, 'Middle Name (as on passport)'), f.text_field(:middle_name) %> 
    <%= element_block f.label(:other_names, 'Other Names'), f.text_field(:other_names) %> 
    <%= element_block f.label(:residence_street_address, 'Street Address'), f.text_field(:residence_street_address) %> 
    <%= element_block f.label(:residence_city, 'City'), f.text_field(:residence_city) %> 
    <%= element_block f.label(:residence_province, 'Province'), f.text_field(:residence_province) %> 
    <%= element_block f.label(:residence, 'Country'), f.text_field(:residence) %> 
    <%= element_block f.label(:residence_postal_code, 'Postal Code'), f.text_field(:residence_postal_code) %> 
    <%= element_block f.label(:birthdate, 'Date of Birth'), f.text_field(:birthdate, :class => 'datepicker', :id => "student_birth_date") %> 
    <%= element_block f.label(:citizenship, 'Country of Citizenship'), f.countries_select(:citizenship) %> 
    <%= element_block f.label(:birth_city, 'Birth City'), f.text_field(:birth_city) %> 
    <%= element_block f.label(:nationality, 'Nationality'), f.countries_select(:nationality) %> 
    <%= element_block f.label(:gender, 'Gender'), f.gender_select(:gender) %> 
    <%= element_block f.label(:email, 'Email'), f.text_field(:email) %> 
    <%= element_block f.label(:desires_esl, 'Does the student wish to participate in CLEP?'), f.bool_yes_no_select(:desires_esl) %> 
    <%= element_block f.label(:may_pay_tuiton, 'Willing to pay tuition'), f.yes_no_select(:may_pay_tuition) %> 
    </dl> 
    <div class="submit"><%= submit_tag("Proceed to Step Two") %></div> 
<% end %> 

Répondre

1

Voilà comment je fini par prendre soin avec accepts_nested_attributes_for

Modèle primaire. (Code Irrelevant remplacé par des ellipses)

class ProfileCore < ActiveRecord::Base 
    set_table_name "profile_core" 
    set_primary_key "STUDENT_ID" 
    belongs_to :agents_profile, :primary_key => "AGENT_ID", :foreign_key => "AGENT_ID" 
    has_one :profile_program, :primary_key => "STUDENT_ID", :foreign_key => "STUDENT_ID" 

    accepts_nested_attributes_for :profile_program 
... 
end 

Modèle secondaire

class ProfileProgram < ActiveRecord::Base 
    set_table_name "profile_program" 
    set_primary_key "STUDENT_ID" 
    belongs_to :profile_core, :primary_key => "STUDENT_ID", :foreign_key => "STUDENT_ID" 

    validates_presence_of :program 
    validates_hsp_program :program 
end 

Nouvelle action dans le contrôleur. (FONCER était hors de propos)

def new 
    @pc = ProfileCore.new 
    @pp = @pc.build_profile_program 
end 

Voir

<% form_for @pc, :url => { :controller => 'core', :action => 'create'} do |f| %> 
    <%= f.error_messages %> 
    <dl> 
    <%= element_block f.label(:contract, 'Contract Year'), f.contract_year_select(:contract) %> 
    <% f.fields_for :profile_program do |pp| %> 
     <%= element_block pp.label(:program, 'Program'), pp.hsp_program_select(:program) %> 
    <% end %> 
    <%= element_block f.label(:passport_number, 'Passport Number'), f.text_field(:passport_number) %> 
... 
<% end %> 
0

L'implémentation de la validation personnalisée n'est pas correcte, essayez quelque chose comme ça: http://marklunds.com/articles/one/312 ou http://chrisblunt.com/blog/2009/04/18/rails-writing-dry-custom-validators/

+0

Je Comprise le validateur lui-même, pas le peu de coups de poing de canard pour le faire fonctionner. Je sais que le validateur est exécuté parce que je peux sortir ou déboguer à l'intérieur avant le validate_each et ça marche. – baudtack