Embed devise form with extra field in different page - ruby-on-rails

I'm using devise+omniaouth for authenticanton. My users also have a profile, with the following relationship;
class User < ActiveRecord::Base
has_many :authentications
has_one :profile
accepts_nested_attributes_for :profile
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
etc.
So my registrations/new.html.erb looks like this:
<% resource.build_profile %>
<%= form_for(resource, :as => resource_name,
:url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for :profile do |profile_form| %>
<h2><%= profile_form.label :name %></h2>
<p><%= profile_form.text_field :name %></p>
<% end %>
<h2><%= f.label :email %></h2>
<p><%= f.text_field :email %></p>
<h2><%= f.label :password %></h2>
<p><%= f.password_field :password %></p>
<h2><%= f.label :password_confirmation %></h2>
<p><%= f.password_field :password_confirmation %></p>
<p><%= f.submit "Sign up" %></p>
<br/>
<%= render :partial => "devise/shared/links" %>
<% end %>
<%= render "links" %>
As you can see, the only attribute that I'm trying to fill from the profile is 'name'. This works correctly and when you try to sign up from /users/sign_up, you have to fill name, email and password.
Now, I'm trying to display this registration window from a modal window, so I created:
/views/devise/menu/_registration_items.html.erb with the same info:
<%= form_for(resource, :as => resource_name,
:url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for :profile do |profile_form| %>
<h2><%= profile_form.label :name %></h2>
<p><%= profile_form.text_field :name %></p>
<% end %>
<h2><%= f.label :email %></h2>
<p><%= f.text_field :email %></p>
<h2><%= f.label :password %></h2>
<p><%= f.password_field :password %></p>
<h2><%= f.label :password_confirmation %></h2>
<p><%= f.password_field :password_confirmation %></p>
<p><%= f.submit "Sign up" %></p>
<br/>
<% end %>
I also added this to the application controller (it works the same way if I put it in the helper):
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
As explained at https://github.com/plataformatec/devise/wiki/How-To%3a-Display-a-custom-sign_in-form-anywhere-in-your-app
Everything works fine except that the name field doesn't dislpay in the form.(For example, the login form that doesn't have that field name works correctly). I guess that I have to map something else, but I don't know what it is.
Thanks!

I forgot to add the
<% resource.build_profile %>
line at the top of the form.

Related

Simple Form simple_fields_for only show last record

I have a nested simple form to edit a user. The user has a profile he/she can update, and a new record is written to the profile table.
simple_fields_for shows all profile records of a user due to the relationship user 1 to many profile records. However, I would like to only show the newest profile record in the form! How can I accomplish that?
<%= simple_form_for(#user) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :lang %>
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= f.input :email %>
<%= f.input :born %>
<%= f.input :gender %>
<%= f.simple_fields_for :profile do |p| %> # the magic needed here
<%= p.input :postal_code %>
<%= p.input :core %>
<%= p.input :daytime %>
<%= p.input :style %>
<% end %>
<% if #is_new %>
<%= f.simple_fields_for :status do |s| %>
<%= s.input :entered, as: :hidden, input_html: { value: Time.current } %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Little late, but accepted answer is not 100% accurate. (Would just make this a comment, but no rep.) I would do this like so:
Assuming you have
class User < ActiveRecord::Base
has_many :profiles
...
def latest_profile
profiles.order(...) # query to get whatever record it is you want
end
end
your simple_fields_for can just be
<%= f.simple_fields_for :profiles, f.object.latest_profile do |p| %>
Note the pluralization of :profiles, and that we don't need to clutter the controller with an additional instance variable because you can access the object in the form. (Using the singular will work I believe, but you will not get params with a key in the form of :profiles_attributes, meaning even more code to account for unique params.)
The edit action:
class user > ApplicationController
...
def edit
#profile = #user.profile.order("saved DESC").first
end
...
end
The working form:
<%= simple_form_for(#user) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :lang %>
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= f.input :email %>
<%= f.input :born %>
<%= f.input :gender %>
<%= f.simple_fields_for :profile, #profile do |p| %> # the magic needed here
<%= p.input :postal_code %>
<%= p.input :core %>
<%= p.input :daytime %>
<%= p.input :style %>
<% end %>
<% if #is_new %>
<%= f.simple_fields_for :status do |s| %>
<%= s.input :entered, as: :hidden, input_html: { value: Time.current } %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>

Rails params[:email] always returning nil

I have the following simple rails page:
<h1> New User </h1>
<%= form_for :user, url:users_path do |f| %>
<p>
<%= f.label :email %>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %>
<%= f.text_field :password %>
</p>
<%= f.submit %>
<% end %>
The create action gets executed and I want to access the :email attribute.
def create
render text: params[:email].inspect
end
The above always displays nil.
form_for :user will place all parameters beneath a :user key
render text: params[:user][:email].inspect

Rendering devise error messages in scoped custom form

I have to Devise models, User and Vendor. I generated the views for Vendor and customized the signup form to suit my needs. I needed to tweak the registrations controller for Vendor, like so:
controllers/vendors/registrations_controller.rb
class Vendors::RegistrationsController < Devise::RegistrationsController
skip_before_filter :require_no_authentication
def create
super
end
protected
def sign_up(resource_name, resource)
true
end
def new
super
end
end
My signup view for Vendor looks like so:
views/vendors/registrations/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:multiparet => :true} ) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :store_name %>
<%= f.text_field :store_name %></div>
<div><%= f.label :contact_name %>
<%= f.text_field :contact_name%></div>
<div><%= f.label :contact_phone %>
<%= f.text_field :contact_phone %></div>
<div><%= f.label :address %>
<%= f.text_field :address %></div>
<div><%= f.label :image %>
<%= f.file_field :image %></div>
<div><%= f.label :email %>
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %>
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "vendors/shared/links" %>
When I attempt to render the page, I get this error:
undefined method `errors' for nil:NilClass
How can I render devise error messages in this situation? Thanks in advance!
I would write this as a comment, but it will be easier to read as an answer:
Perhaps you could try replacing devise_error_messages! with a standard Rails error display:
<% if resource.errors.any? %>
<div class="error">
<strong><%= pluralize(resource.errors.count, "Error") %></strong>
<ul>
<% resource.errors.each do |attr,msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Not getting field_with_errors for some reason

I'm using Rails 3.2.2 and am not getting the field_with_errors div when the validation fails.
views/sessions/new.html.erb
<%= form_tag sessions_path do %>
<p><%= label_tag :email %><br />
<%= email_field_tag :email %></p>
<p><%= label_tag :password %><br />
<%= password_field_tag :password %></p>
<p><%= submit_tag "Log in" %></p>
<% end %>
controllers/sessions_controller.rb
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password]) && user.account.subdomain == request.subdomain
session[:user_id] = user.id
redirect_to home_path
flash[:notice] = "Logged in!"
else
flash.now[:error] = "Invalid email or password"
render 'new'
end
end
models/user.rb
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation
has_secure_password
validates :email, :presence => true, :uniqueness => true
validates :password, :presence => true, :on => :create
I'm getting the flash message, but my view doesn't render the field_with_errors wrapper divs if the validation fails. Any ideas?
Thanks.
It's no longer included by default, you need to render your own error messages.
Here's some sample code generated in a scaffold for a Post model:
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
You can then extract that into a partial for re-use with your other models.
I think the field_with_errors functionality only works with form_for. If you want it, you could change your authenticate method to add errors to the the #user object (it will have to be an instance variable for this to work), and then change your form to:
<%= form_for(#user) do |f| %>
<%= f.error_messages %>
<p><%= f.label :email %><br />
<%= f.email_field :email %></p>
<p><%= f.label :password %><br />
<%= f.password_field :password %></p>
<p><%= f.submit "Log in" %></p>
<% end %>

nested attributes for registration form

I have a user and a company model where a user has_one company and company belongs to user. I just wanted to save the company field from the registration form to the company table,where the company table columns are user_id and company_name. I used the following to do this in my User.rb
has_one :company, :class_name => 'Company', :foreign_key => :user_id, :dependent => :destroy
accepts_nested_attributes_for :company
And My registration form looks like this
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :firstname %><br/>
<%= f.text_field :firstname %></p>
<p><%= f.label :lastname %><br/>
<%= f.text_field :lastname %></p>
<p><%= f.label :email %><br/>
<%= f.email_field :email %></p>
<p><%= f.label :password %><br/>
<%= f.password_field :password %></p>
<p><%= f.label :password_confirmation %><br/>
<%= f.password_field :password_confirmation %></p>
<%= fields_for :company do |builder| %>
<%= builder.label :company %>
<td><%= builder.text_field :company_name%> </td>
<% end %>
<p><%= f.submit "Sign up" %></p>
<% end %>
<%= render :partial => "devise/shared/links" %>
Is it necessary to have a hidden field for user_id for company table or it will get automatically added, I also tried overriding the create method of registration controller it works but the devise error messages are not working. Can anyone help me out in this. I dont know what I have missed. Thanks in advance.
1) No, you don't need a user_id hidden field, just use fields_for as a method
<%= f.fields_for :company do |builder| %>
...
<% end %>
2) fields_for will not be shown if user does not have associated companies yet, and that will happen with new record, so you can do
<% f.object.company.build %> as a hack :)
or do it the proper way in a controller action

Resources