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
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
I want to make chain selects part inside my Formtastic form. But is it possible to set custom ids for multiple selects for future AJAX replacement?
This doesn't work:
<%= semantic_form_for [:admin, #production_year] do |f| %>
<%= f.inputs do %>
<%= f.input :car_model, :label => "CarModel", :as => :select, :collection => Brand.find(:all, :order => "name ASC"), :id => "brand_id" %>
<% end %>
<% end %>
Options should be passed to the input_html hash, like so:
<%= f.input :car_model, :input_html => { :id => "brand_id" } %>
I use form_for to save a model object site
<% form_for :site :url => {:controller => 'site', :action => 'add_site' } do |f| -%>
<%= f.text_field :protocol, :size => 127, :style => 'width:255px' , :value => "http://"%>
<%= f.text_field :site_name, :size => 127, :style => 'width:255px' , :value => "www."%>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.hidden_field :status, :value => 'Not Verified' %>
<% end -%>
here the field protocol is not a instance of the model site. but i just want to pass to the action add_site so that i can use as params[:protocol]
what should i do to achieve this?
You can set something like this:
<%= text_field_tag :protocol %>
To the action of the controller you can refer to this as params[:protocol]
Add it to your site model as an attribute accessor:
attr_accessor :protocol
See http://railscasts.com/episodes/16-virtual-attributes .
I have a form I'm trying to set up ...
Users can have many posts, and each post can have many people watching it.
The Watch model is set up polymorphically as 'watchable' so it can apply to different types of models. It has a user_id, watchable_id, watchable_type and timestamps as attributes/fields.
This is soley so that when people comment on a post, users watching the post can get an email about it.
What I'm trying to do is show the user a list of users that they can tag on each post, which is not problem. This is what I'm using right now
http://pastie.org/940421
<% semantic_form_for #update do |f| %>
<%= f.input :subject, :input_html => { :class => 'short' } %>
<%= f.input :site, :include_blank => false, :input_html => { :class => 'short' } %>
<label>Tag Users (they will get notified of this update)</label>
<%= f.input :user, :as => :check_boxes, :label => ' ', :wrapper_html => { :class => "radiolist clearfix" }, :for => :watch, :name => "Watch" %>
<%= f.input :note, :label => 'Update'%>
<% f.buttons do %>
<%= f.commit_button :button_html => { :class => 'submit' } %>
<% end %>
<% end %>
The problem with this, is that when you go to edit an update/post ... all the checkboxes are prechecked ... I want it to pre-check only users who are currently watching the post.
To further clarify ... this is the hacky way I'm getting it to do what I want right now
<ul class="radiolist clearfix">
<% #users.each do |user| %>
<li>
<%= check_box_tag 'user_ids[]', user.id, #watches.include?(user.id) ? true : false -%>
<%= h user.name -%>
</li>
<% end %>
</ul>
where #watches is just an array of user ids
#watches = #update.watches.map{|watcher| watcher.user_id}
For anyone else having the same issue:
<%= f.input :some_input, :as => :boolean, :input_html => { :checked => 'checked' } %>
For multiple check boxes, this way:
<%= f.input :tags, :as => :check_boxes, :collection => some_map.collect { |c| [c[:name], c[:id], {:checked=> tag_ids.include?(c[:id])}] } %>
If you need the state of the checkbox to reflect the value of :some_input
<%= form.input :some_input, :as => :boolean, :input_html => { :checked => :some_input? } %>
In your model..
def some_input?
self.some_input ? true : false
end
Set the boolean attribute's value to 'true' in the controller before your render the form. That should make Formtastic default the checkbox to 'checked'.