Rails form duplicaiton - ruby-on-rails

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

Related

Ruby on Rails - Not saving User - Nested Attributes and Nested Forms

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

undefined method `before_create'

I have a User model and a Company model linked like this:
class User < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company
end
class Company < ActiveRecord::Base
has_many :users
end
On the sign in page, I want the user to set up both his info (mail, password) and his company info (several fields). So my form looks like this:
<%= simple_form_for #user, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.input :email, :required => true, :placeholder => "user#domain.com" %>
<%= f.input :password, :required => true %>
<%= f.input :password_confirmation, :required => true %>
<h2>Company info</h2>
<%= simple_fields_for :company, :html => { :class => 'form-horizontal' } do |fa| %>
<%= fa.input :name %>
<%= fa.input :url %>
<%= fa.input :description, :as => :text, :input_html => { :cols => 60, :rows => 3 } %>
<%= fa.input :logo %>
<%= fa.input :industry %>
<%= fa.input :headquarters %>
<% end %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
root_url, :class => 'btn' %>
</div>
<% end %>
My user model has a company_id:integer field. So logically, when I sign in the user, the first thing to do is to create the Company before the User and then give to the user creation model the appropriate company_id. So I wrote this:
class UsersController < ApplicationController
before_create :create_company
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Registration successful."
else
render :action => 'new'
end
end
private
def create_company
#company = Company.new(params[:company])
if #company.save
self.company_id = #company.id
else
render :action => 'new'
end
end
end
Problem is: when accessing /users/new I get this error:
undefined method `before_create' for UsersController:Class
What's going wrong? I checked, before_create has not been deprecated, I'm in Rails 3.2.8. This is probably something stupid with my create_company method but I can't figure why...
Thanks a lot for helping!
before_create is a hook method belonging to ActiveRecord
before_filter is a hook method belonging to Controller.
so I suggest you to re-build your code after you make clear which is which. ^_^

Rails simpleform pre data

How do I make a simple form association have pre data when editing?
My form:
<h1>Editing kategori</h1>
<%= simple_form_for(#konkurrancer, :url => {:action => 'update', :id => #konkurrancer.id }) do |f| %>
<%= f.association :kategoris %>
<%= f.button :submit, :value => 'Edit konkurrence' %>
<% end %>
You almost did it:
<%= f.button :submit, :value => 'Edit konkurrence', :data_pre => "whatever here" %>
Your best bet is to do something like this in your controller:
def edit
#konkurrancer = Konkurrancer.new(:title => "hello wurld", :description => "blah blah blah", :nuclear_level => 10)
end
Then your form should automatically populate these values as "pre data".

Partial containing a form appears in both controllers, but fails to submit on one of them

I have a partial that contains a form:
<% form_for :message, :url => { :action => "create" }, :html => { :id => 'form' } do |f| %>
<%= f.error_messages %>
<%= f.label :title, "title" %>
<%= f.text_field :title %>
<%= f.label :tag, "tag" %>
<% if controller.controller_name == "tags" %>
<%= f.text_field :tag_list, :value => #title %>
<% else %>
<%= f.text_field :tag_list %>
<% end %>
<%= f.label :name, "name" %>
<%= f.text_field :name %>
<%= f.label :email, "email" %>
<%= f.text_field :email %>
<%= f.label :title, "message" %>
<%= f.text_area :content %>
<%= f.submit 'submit' %>
<% end %>
I'm using this in two controllers: messages and tags. It works fine in the messages controller but not in the tags controller. When it's rendered in tags#show it autofills the tag field. When a message is submitted from tags#show I'm redirected to the root of the website with a flash error "Tag does not exist."
tags controller:
class TagsController < ApplicationController
before_filter :redirect_if_doesnt_exist#, :only => :show
def show
#title = Tag.find(params[:id]).name
#tag = Tag.find(params[:id])
#entries = Entry.paginate(Entry.find_tagged_with(#tag),
:page => params[:page], :per_page => 10, :order => "name")
#messages = Message.paginate(Message.find_tagged_with(#tag),
:page => params[:page], :per_page => 10, :order => "updated_at DESC")
#related_entries = Entry.tagged_with(#tag, :on => :tags)
#related_tags = #related_entries.collect{|x|x.tags}.flatten.uniq
#related_tags.delete(#tag)
end
private
# Redirect if requested tag does not exist
def redirect_if_doesnt_exist
#tag = Tag.find(params[:id]) rescue nil
if #tag.nil? # maybe "or #tag.empty?" could solve the empty tag issue
flash[:error] = 'Tag does not exist.'
redirect_to '/'
end
end
end
In case it isn't clear: The partial is shown in the view, the form within it just doesn't submit the data from the tags controller and is redirected. The partial works fine from the messages controller. This is a Rails 2.3.x application.
Thank you for reading my question, your time is appreciated.
Your problem is the URL of the form partial is only the action:
<% form_for :message, :url => { :action => "create" }, :html => { :id => 'form' } do |f| %>
If you include this in a view that isn't under messages_controller, it'll call the wrong action. If you include this ina a tags view, it'll try to call the create action for tags_controller instead.
It'll probably work if you just add the controller too:
<% form_for :message, :url => { :controller => :messages, :action => :create }, :html => { :id => 'form' } do |f| %>

Rails Multiform structure seems a bit off

Ok so I am having a problem with doing multiple forms in rails. here is the code below
Models
class Profile < ActiveRecord::Base
belongs_to :user
has_attached_file :avatar, :styles => { :medium => "134x137>", :thumb => "111x111>", :tiny => "32x38>" }
validates_attachment_content_type :avatar, :content_type => ['image/pjpeg','image/jpeg', 'image/x-png', 'image/png', 'image/gif']
class User < ActiveRecord::Base
has_one :profile, :dependent => :destroy
Profile Controller
def edit
#user = User.find(params[:id])
#profile = #user.profile
end
Profiles Edit View
<% form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<input id="send_update" name="send" type="submit" value="Update" />
<% end %>
<% form_for #profile , :html => { :multipart => true } do |f| %>
<%= render :partial => 'form', :locals => {:f => f, :profile => #profile, :title => 'Edit Profile'} %>
<%= submit_tag 'Update', :style => 'text_align:right'%>
<% end %>
Profile _form partial
<label>Upload Avatar</label>
<tr><%= f.file_field :avatar %></tr>
So basically I have two forms in the edit view and when i click on the second Update to update the avatar I go to the users update and i get this flash error "Sorry, something went wrong"
def update
#user = User.find(params[:id])
current_email = #user.email
if #user.update_attributes(params[:user])
UserMailer.deliver_email_changed (#user) if email_changed?(current_email, #user.email)
flash[:notice] = "<h1>Account updated!</h1>"
redirect_to edit_user_path(#user)
else
flash.now[:error] = "Sorry, something went wrong"
render :action => :edit
end
end
My questions are this
Is there a better way to structure this so maybe i have one form?
Why is it not saving now and whats causing the issue?
The method you are using to update is wrong, it is syntactically invalid (you're missing an end). It should be:
def update
#user = User.find(params[:id])
current_email = #user.email
if #user.update_attributes(params[:user])
UserMailer.deliver_email_changed (#user) if email_changed?(current_email, #user.email)
flash[:notice] = "<h1>Account updated!</h1>"
redirect_to edit_user_path(#user)
else
flash.now[:error] = "Sorry, something went wrong"
render :action => :edit
end
end
It should be two forms indeed, as I'm guessing you don't want any of the values of one form to submit if the user performs the other action.
Now, organize your controllers. You are calling #user = User.find(params[:id]) on your ProfilesController, but the id you're passing is an user's one. Either this should be on the user's controller, and update the associated profile from there, or you should receive the id of the profile object instead.
I'd go with the first one. You can update the Profile object of a user using accepts_nested_attributes_for, and your forms would be like:
<% form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.submit, :id => ... %>
<% end %>
<% form_for #user, :html => { :multipart => true } do |f| %>
<% f.fields_for :profile do |profile_form| %>
<%= render :partial => 'form', :locals => {:f => profile_form, :title => 'Edit Profile'} %>
<%= submit_tag 'Update', :style => 'text_align:right'%>
<% end %>
<% end %
If the error is that the password cannot be blank, may be due to a validates_presence_of :password, :password_confirmation. You should use a conditional validation there
Troubleshooting would help:
Remove the if/else and keep the #user.update_attributes(params[:user]). Rails would give you a more detailed error message.
Check the form structure (html source) especially for field naming.
Check the log files for DB statements
HTH

Resources