I have this model User, Entidade and Candidato.
class User < ActiveRecord::Base
has_one :entidade
has_one :candidato
accepts_nested_attributes_for :entidade
accepts_nested_attributes_for :candidato
class Candidato < ActiveRecord::Base
belongs_to :user
class Entidade < ActiveRecord::Base
belongs_to :user
Basically in order to register you need to specify if you want to be an Entidade or a Candidato. They have some shared attributes that i put in the User table. And the non shared attributes stay in the respective table.
This is the form:
<%= simple_form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages' %>
<%= f.input :email %>
<%= f.input :role, :as => :hidden, :input_html => { :value => "candidato" } %>
<%= f.input :password %>
<%= f.input :password_confirmation, label: "Confirme a password" %>
<%= f.input :nome %>
<%= f.input :foto, :label => "Foto" %>
<%= f.input :cod_postal, :label => "Código-Postal" %>
<%= f.input :localidade %>
<%= f.input :contacto1, :label => "Contactos" %>
<%= f.input :contacto2, label: false %>
<%= f.input :pagina, :label => "Página Pessoal" %>
<%= f.fields_for :candidato do |ff| %>
<%= ff.input :data_nascimento, :label => "Data de Nascimento" %>
<%= ff.input :bi, :label => "Bilhete de Identidade" %>
<%= ff.input :cv, :label => "Curriculum Vitae" %>
<%= ff.label :area_profissional, :label => "Área Profissional" %>
<%= ff.select :area_profissional, ["Programador_Web", "Programador_Java","Gestor"], :label => "Área Profissional" %>
<%= ff.input :apresentacao, :label => "Apresentação" %>
<%= ff.select :nivel_hab, ["Secundário","Licenciatura","Mestrado","Doutoramento"], :label => "Nível de Habilitações" %>
<%= ff.input :hab_literaria, :label => "Habilitações Literárias" %>
<%= ff.select :situacao_prof, ["Empregado","Desempregado"], :label => "Situação Profissional" %>
<%= ff.input :exp_profissional, :label => "Experiência Profissional" %>
<% end %>
<%= f.submit "Registar", class: "btn btn-large btn-primary" %>
<% end %>
And I can't create the damn User. It keeps rendering the new page. What the hell is wrong.
This is my Controller:
class UsersController < ApplicationController
def new
#user = User.new
if params[:param] == "candidato"
#role = "candidato"
##user.candidato = Candidato.new
#user.build_candidato
else
#role = "entidade"
##user.entidade = Entidade.new
#user.build_entidade
end
end
def create
#user = User.new(user_params)
if user_params[:role] == "candidato"
#user.build_candidato(user_params[:candidato_attributes])
##user.candidato = Candidato.new(user_params[:candidato_attributes])
if #user.save
#Sucesso
redirect_to root_path
else
#Falhou
#role = "candidato"
render 'new'
end
else
##user.entidade = Entidade.new(user_params[:entidade_attributes])
#user.build_entidade(user_params[:entidade_attributes])
if #user.save
#Sucesso
redirect_to root_path
else
#Falhou
#role = "entidade"
render 'new'
end
end
end
private
def user_params
params.require(:user).permit(:role,:email,:nome,:password,:password_confirmation,:pagina,:contacto1,:contacto2,:foto,:cod_postal,:localidade, :candidato_attributes => [:data_nascimento,:bi,:cv,:area_profissional,:apresentacao,:nivel_hab,:hab_literaria,:situacao_prof,:exp_profissional], :entidade_attributes => [:nip,:apresentacao,:atividade])
end
end
If someone knows what's wrong please tell me
Problem is here in your create method you are building dependent object twice and you have has_one relationship. You object for dependent model already created on new action on parent.
Your controller should look like :
def create
#user = User.new(user_params)
if #user.save
redirect_to root_path
else
#role = user_params[:role]
render 'new'
end
end
Form should look like :
<%= simple_form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages' %>
<%= f.input :email %>
<%= f.input :role, :as => :hidden, :input_html => { :value => #role } %>
<%= f.input :password %>
<%= f.input :password_confirmation, label: "Confirme a password" %>
<%= f.input :nome %>
<%= f.input :foto, :label => "Foto" %>
<%= f.input :cod_postal, :label => "Código-Postal" %>
<%= f.input :localidade %>
<%= f.input :contacto1, :label => "Contactos" %>
<%= f.input :contacto2, label: false %>
<%= f.input :pagina, :label => "Página Pessoal" %>
<% if #role == "candidato" %>
<%= f.fields_for :candidato do |ff| %>
<%= ff.input :data_nascimento, :label => "Data de Nascimento" %>
<%= ff.input :bi, :label => "Bilhete de Identidade" %>
<%= ff.input :cv, :label => "Curriculum Vitae" %>
<%= ff.label :area_profissional, :label => "Área Profissional" %>
<%= ff.select :area_profissional, ["Programador_Web", "Programador_Java","Gestor"], :label => "Área Profissional" %>
<%= ff.input :apresentacao, :label => "Apresentação" %>
<%= ff.select :nivel_hab, ["Secundário","Licenciatura","Mestrado","Doutoramento"], :label => "Nível de Habilitações" %>
<%= ff.input :hab_literaria, :label => "Habilitações Literárias" %>
<%= ff.select :situacao_prof, ["Empregado","Desempregado"], :label => "Situação Profissional" %>
<%= ff.input :exp_profissional, :label => "Experiência Profissional" %>
<% end %>
<%else%>
<%= f.fields_for :entidade do |ff| %>
<%= ff.input :atividade, :label => "atividade" %>
<%= ff.input :apresentacao, :label => "apresentacao" %>
<%= ff.input :nip, :label => "nip" %>
<% end %>
<% end %>
<%= f.submit "Registar", class: "btn btn-large btn-primary" %>
<% end %>
You also have to add :id and _destroy in attributes. It will used at the time of edit and delete child model.
def user_params
params.require(:user).permit(:role,:email,:nome,:password,:password_confirmation,:pagina,:contacto1,:contacto2,:foto,:cod_postal,:localidade, :candidato_attributes => [:id, :data_nascimento,:bi,:cv,:area_profissional,:apresentacao,:nivel_hab,:hab_literaria,:situacao_prof,:exp_profissional, :_destroy], :entidade_attributes => [:id, :nip,:apresentacao,:atividade, :_destroy])
end
#app/controllers/users_controller.rb
Class UsersController < ApplicationController
def new
#user = User.new
#user.send("build_#{params[:param]}")
end
def create
#user = User.new user_params
#user.save
end
private
def user_params
params.require(:user).permit(:role,:email,:nome,:password,:password_confirmation,:pagina,:contacto1,:contacto2,:foto,:cod_postal,:localidade, :candidato_attributes => [:data_nascimento,:bi,:cv,:area_profissional,:apresentacao,:nivel_hab,:hab_literaria,:situacao_prof,:exp_profissional], :entidade_attributes => [:nip,:apresentacao,:atividade])
end
end
When you pass nested attributes, you only need to build the initial associative object
In your create method, you're building the associative data again. A much better way will be to use the code above (albeit edited to represent your redirects), to create the User object
Validations aside, I don't see any reason why the above code wouldn't work with your form
Related
I have the below form which works absolute fine but when submitted the :event field returns an ID in the mailer, any ideas how to prevent this?
Form
<%= simple_form_for #sponsorship_inquiry, :method => :post do |f| %>
<%= f.input :spam, as: :hidden %>
<%= f.input :name %>
<%= f.input :phone %>
<%= f.input :email %>
<%= f.input :job_title %>
<%= f.input :company %>
<%= f.input :event, :collection => Event.where(:end_date.gt => Date.today, :is_live => 'true') %>
<%= f.input :message, as: :text, :input_html => { :cols => 5, :rows => 6 } %>
<%= f.button :submit %>
<% end %>
Mailer
Name: <%= #sponsorship_inquiry.name %>
Phone: <%= #sponsorship_inquiry.name %>
E-Mail: <%= #sponsorship_inquiry.email %>
Job Title: <%= #sponsorship_inquiry.job_title %>
Company: <%= #sponsorship_inquiry.company %>
Event: <%= #sponsorship_inquiry.event %>
Message: <%= #sponsorship_inquiry.message %>
Controller
def new
#sponsorship_inquiry = SponsorshipInquiry.new
end
def create
# Hidden field for bots/spiders
redirect_to new_inquiry_path and return if params[:spam].present?
#sponsorship_inquiry = SponsorshipInquiry.new(params[:sponsorship_inquiry])
if #sponsorship_inquiry.valid?
SponsorshipInquiryMailer.admin(#sponsorship_inquiry).deliver
redirect_to sponsorship_inquiries_path
else
render :new
end
end
Need your SponsorshipInquiry model.
If you have
class SponsorshipInquiry < ActiveRecord::Base
belongs_to :event
end
try send <%= #sponsorship_inquiry.event.name %> or whatever )
Or you need to parse needed value from the form if "event" is only field not associated with Event model.
IMHO
If your question is "can I modify the form so that I automatically (magically?) get an object as a param?", the answer is definetly no.
What you have to do is to search the event object in the database based on the received id.
I want to add delete button in actions. but all it does is js goback. I tried <%= f.actions %> didn't show the delete button. below is my effort to add it manually.
<% if can? :update, #parking_branch %>
<%= semantic_form_for #parking_branch do |f| %>
<%= f.semantic_errors %>
<%= f.inputs do %>
<%= f.input :parking_company_id, :as => :select, :collection => Hash[ParkingCompany.all.map {|c| [c.company_name,c.id]}], :required => true %>
<%= f.input :branch_name, :required => true %>
<%= f.input :email, :required => true %>
<%= f.input :telephone, :required => false %>
<%= f.input :latitude, :hint =>"Automatically filled based on address" %>
<%= f.input :longitude, :hint =>"Automatically filled based on address" %>
<%= f.input :airport, :required => true %>
<%= f.input :address1 %>
<%= f.input :address2, :required => false %>
<%= f.input :address3, :required => false %>
<%= f.input :city %>
<%= f.input :county %>
<%= f.input :postcode %>
<%= f.input :country, :as => :country, :priority_countries => ["United Kingdom"], :required => true %>
<% end %>
<br />
<%= f.actions do %>
<%= f.action :submit, :button_html => {:class => 'btn-primary', :disable_with => 'Please Wait...' } %>
<%= f.action :cancel, :button_html => {:class => 'btn-danger', :disable_with => 'Please Wait...', :method => :delete } %>
<% end %>
<% end %>
<% else %>
<br />
<h1> You are not authorised to do this! <h1>
<% end %>
I have destroy action in my controller too
I haven't had a problem with validations before but this time I am having issues with nested_form validations. I am using Twitter Bootstrap and can get flash errors to show with, say, this:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
render :action => 'new'
end
end
For my flash messages I use this in my app/layouts
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
</div>
<% end %>
So I thought I would try and just get one of the validators working, so my model
class Recipe < ActiveRecord::Base
belongs_to :user
delegate :name, :to => :user, :prefix => :user, :allow_nil => true
belongs_to :country
has_many :ingredients
has_many :preperations
has_many :favourites
validates_presence_of :dish_name
and my form
<%= nested_form_for #recipe do |f| %>
<div class="field_with_errors">
<%= f.label :dish_name, "Dish Name" %>
<%= f.text_field :dish_name, :placeholder => "Enter Dish Name" %>
</div>
<%= f.label :country_id, "Country Of Origin" %>
<%= f.collection_select(:country_id, Country.all, :id, :name, :prompt => 'Please select country') %>
<%= f.label :category, "Category" %>
<%= f.select :category, [['Starter'], ['Main Course'], ['Desserts'], ['Vegeterian']], {:include_blank => 'Please Select'} %>
<%= f.label :difficulty, "Difficulty Level" %>
<%= f.select :difficulty, [['Beginner'],['Intermediate'],['Expert']], {:include_blank => 'Please Select'} %>
<%= f.label :preperation_time, "Preperation Time (Mins)" %>
<%= f.select :preperation_time, [['15-30 Mins'],['30-60 Mins'],['60-120 Mins']], {:include_blank => 'Please Select'} %>
<%= f.fields_for :ingredients do |ing| %>
Ingredient<br>
<%= ing.text_field :ingredient_name , :placeholder => "Enter Ingredient Here" %><br>
<% end %>
<%= f.link_to_add "Add an Ingredient", :ingredients %><br>
<%= f.fields_for :preperations do |prep| %>
Preperation Step<br>
<%= prep.text_field :prep_steps , :placeholder => "Enter step Here" %><br>
<% end %>
<%= f.link_to_add "Add a step", :preperations %><br>
<%= f.label :description, "Description of Recipe" %>
<%= f.text_area :description, :size=> "60x10" %></br>
<%= f.file_field :avatar %><br>
<%= f.submit "Submit Recipe" %>
<% end %>
I am fairly new to Rails so I may have missed something fundamental, or is it because it is a nested form and it behaves differently?
Edit
Output of <%= flash debug %>:
--- !ruby/object:ActionDispatch::Flash::FlashHash
used: !ruby/object:Set
hash: {}
closed: false
flashes: {}
now:
It seems you're not actually providing your flash hash with any messages to work with. A quick solution might be something like:
def create
#recipe = current_user.recipes.new(params[:recipe])
if #recipe.save
redirect_to my_recipes_path, :notice => "Thanks #{current_user.name} Recipe sucessfully created."
else
flash[:error] = #recipe.errors.full_messages.to_sentence
render :action => 'new'
end
end
I have form partial that allows the user to enter the subject and message that will be included in the outbound email. I want to allow the users to select the recipients of the email from the contacts that are associated with the invoice that the email belongs to. The email recipients that are selected through the nested form are to be stored in a separate table.
class EmailRecipient < ActiveRecord::Base
attr_accessible :contact_id, :email_id
belongs_to :email
end
class Email < ActiveRecord::Base
attr_accessible :subject, :message, :invoice_id, :email_recipients_attributes
belongs_to :invoice
has_many :email_recipients
accepts_nested_attributes_for :email_recipients
end
<%= simple_form_for [:invoice, #email], html: {class: "form-horizontal"} do |f| %>
<%= f.error_notification %>
<% #invoice.contacts do |c|%>
<%= f.fields_for :email_recipients do |builder| %>
<%= builder.input :contact_id, :as => :check_boxes %>
<%= c.name %><br/>
<% end %>
<% end %>
<%= f.input :subject, :as => "string" %>
<%= f.input :message, :input_html => { :class => 'span7', :rows => 10 } %>
<div class="form-actions">
<%= f.button :submit, "Send Invoice", :class => 'btn-warning' %>
<%= link_to 'Cancel', invoice_path(#invoice), :class => 'btn' %>
</div>
<% end %>
This isn't the prettiest answer, so I would love to see a better solution, but it gets the job done until my skills improve.
In the controller for the parent form I added:
#invoice.contacts.each { |c| #email.email_recipients.build(contact_id: c.id) }
This builds the records for all contacts whether they are needed or not. Then in the form partial I modified the nested form:
<%= simple_form_for [:invoice, #email], html: {class: "form-horizontal"} do |f| %>
<%= f.error_notification %>
<% count = 0 %>
<%= f.simple_fields_for :email_recipients do |email_recipients_form| %>
<%= email_recipients_form.input :_destroy, as: :boolean, :label => false do %>
<%= email_recipients_form.check_box :_destroy, {}, "false", "true" %>
<% contact = #invoice.contacts.find(#email.email_recipients[count].contact_id) %>
<%= contact.name + " (" + contact.email + ")" %>
<% end %>
<%= email_recipients_form.input :contact_id, as: :hidden %>
<% count += 1 %>
<% end %>
I have a form wizard setup with 4 steps that all work on the same model.
When I fill out the first one and click submit (and am redirected to step 2) the form is already filled out and a duplicate, identical form added below. This happens for each step.
How can i render a completely new form after i click submit on step 1 and am taken to 2 (or 3/4)?
step 1
<%= simple_form_for #user, url: wizard_path do |f| %>
<h2 class="signup">Step 3: Friends Birthday</h2>
<%= f.simple_fields_for :events do |event_f| %>
<%= event_f.input :name, :placeholder => 'Enter Persons Name' %>
<%= event_f.input :date, :as => :date_picker, :input_html => { :class => 'special' } %>
<%= event_f.input :reccuring, :label => false, :inline_label => 'Remind me of this event every year?' %>
<h3>Choose up to 3 interests for this person</h3>
<%= event_f.association :interests, :label => false, :as => :check_boxes %>
<%= event_f.input :kind, :as => :hidden, :input_html => { :value => "Birthday" } %>
<%end%>
<%= link_to "skip this step", next_wizard_path %>
<%= f.button :submit, 'Submit' %>
<%end%>
step 2
<%= simple_form_for #user, url: wizard_path do |f| %>
<h2 class="signup"> Married? Add your anniverarsy</h2>
<%= f.simple_fields_for :events do |anniversary_f| %>
<%= anniversary_f.input :name %>
<%= anniversary_f.input :date, :as => :date_picker, :input_html => { :class => 'special' } %>
<h3>Choose up to 3 interests for this person</h3>
<%= anniversary_f.association :interests, :as => :check_boxes, :label => false %></li>
<%= anniversary_f.input :kind, :as => :hidden, :input_html => { :value => "Anniversary" } %>
<%end%>
<%= link_to "skip this step", next_wizard_path %>
<%= f.button :submit, 'Submit' %>
<%end%>
Controllers
events_controller.rb
def new
#user = current_user
#event = Event.new
end
def create
#user = current_user
#event = Event.new(params[:event])
#event.user = User.find(current_user.id)
end
users_controller
class UsersController < ApplicationController
before_filter :authenticate_user!
def create
#user = User.new(params[:user])
if #user.save
redirect_to user_steps_path
else
render :new
end
end
When you complete one step then intilize new object and bind this second form to new object.Repeat this step for 3rd and 4th form.
Mean every time initilize
#user = User.new