Rails project with materialize framework, what I am trying to do is rendering a form in a modal.
Therefore I have in the application.html.erb:
<!-- Modal Structure -->
<div id="signupmodal" class="modal">
<div class="modal-content">
<%= render template: "users/new" %>
</div>
</div>
The rendered template looks like this:
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<div class="row">
<div class="row col s6">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
</div>
<%= f.submit 'Create my account', class: "btn waves-effect waves-light orange darker-1" %>
<% end %>
But because the rendered template has its own controller, I get the
First argument in form cannot contain nil or be empty
error, because it doesn't know the #user in the application controller. What is the best way to avoid this error?
Related
I have a application controller like this :
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :description, :city_id, :golf_level])
end
end
and a form sign up with device like this :
<h2 class='container'>Inscription</h2>
<div class="tab-pane show active" id="component-1-1" role="tabpanel" aria-labelledby="component-1-1">
<div class="component-example">
<div class='container'>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<div class='row'>
<div class="col-md-6">
<%= render "devise/shared/error_messages", resource: resource %>
<div class='field form-group'>
<%= f.label 'Prénom' %><br>
<%= f.text_field :first_name, class: 'form-control' %>
</div>
<div class='field form-group'>
<%= f.label 'Nom' %><br>
<%= f.text_field :last_name, class: 'form-control' %>
</div>
<div class="field form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
</div>
<div class='field form-group'>
<%= f.label 'Niveau' %>
<%= select_tag(:golf_level, options_for_select([['débutant', 'débutant'], ['intermediaire', 'intermediaire'], ['confirmer', 'confirmer']])) %>
</div>
</div>
<div class="col-md-6">
<div class="field form-group">
<%= f.label 'Mot de passe' %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password", class: 'form-control' %>
</div>
<div class="field form-group">
<%= f.label 'Confirmer mot de passe' %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control' %>
</div>
<div class='field form-group'>
<%= f.label 'Ville' %>
<%= select_tag(:city_id, options_for_select( City.all.collect { |city| [city.name, city.id] }, {target_blank: true} )) %>
</div>
<div class='field form-group'>
<%= f.label 'Description'%>
<%= f.text_area :description, size: "60x5", class: 'form-control'%>
</div>
</div>
<div class="actions">
<%= f.submit "Inscription", class: 'btn btn-primary' %>
</div>
<% end %>
<button class='btn btn-primary' style="margin-left:20px;"><%= render "devise/shared/links" %></button>
</div>
</div>
</div>
</div>
My problem is maybe stupid but : When i create a User with this form the selects tags golf_level and city_id are not save in db but all other yes. In device doc I don't find special way for select form.
Ok, your parameters are passed, but not within proper namespace. Instead of select_tag you should use f.select method:
<%= f.select(:city_id, options_for_select(City.pluck(:name, :id), target_blank: true )) %>
And likewise for the second of your params.
Exercise 2 of Hartl's Rails Tutorial chapter 10.1.1 asks to DRY out the 'new' and 'edit' views by creating a partial for the user form. As described in the exercise, an earlier exercised resulted in a discrepancy that I need to address in the partial. I am hoping this will be an easy fix. Here's my code:
This is the form partial:
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: #user %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
<% end %>
Drying out this edit.html.erb as such, using the form partial works fine:
<% provide(:title, 'Edit user') %>
<% provide(:button_text, 'Save changes') %>
<h1>Update your profile</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= render 'form' %>
<div class="gravatar_edit">
<%= gravatar_for #user %>
Change
</div>
</div>
</div>
This is my new.html.erb view, which should render the form partial to replace the form. The discrepancy is in the beginning of the form, where the parameters for form_for include "#user" AND "url: signup_path" :
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user, url: signup_path) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
Then, the improved, DRYed out view should be something like this, with some tweaks to handle the discrepancy.
<% provide(:title, 'Sign up') %>
<% provide(:button_text, 'Create my account') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= render 'form' %>
</div>
</div>
Back to the question: How can I edit the form partial to handle this discrepancy? Many thanks for reading and helping out this rails newbie!
Another option is to use the new_record? method.
So your form_for would look like this:
<%= form_for( #user, url: #user.new_record? ? signup_path : user_update_path %>
Here are the docs for new_record?.
I like to use new record for simple things like changing button text in the view. Here's an example:
<%= submit_tag(object.new_record? ? 'Update' : 'Create' , class: 'nice') %>
One option is to pass in a local variable to the partial:
<%= render 'form', url: signup_path %>
Then in the form partial:
<%= form_for(#user, url: url) do |f| %>
You can now pass in different paths for the form on a per-render basis.
I want to add the option for the user to edit his email/password/image... from the /settings page not from the /users/edit page. So I copied the code to the settings page
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control'%>
</div>
<div class="form-group">
<%= f.label :cover %>
<%= f.file_field :cover, class: 'form-control'%>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
but it returned this
undefined local variable or method `resource' for #<#<Class:0x007f60245ab9b0>:0x007f6026f58358>
What should I add to my controller?
When ever you want to perform any custom actions, first create an action in a controller, then a route to it and then the view file.
resource object is only available in devise routes.
So, first add a method named settings in any controller eg: say userscontroller.
class UsersController < ApplicationController
def settings
#user = current_user
end
end
Then in routes.rb, add a route which points to this action with a route named '/settings'
get '/settings' => 'users#settings', as: :settings
Now, in app/views/users/settings.html.erb
<%= form_for(#user, url: registration_path(#user), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, class: 'form-control'%>
</div>
<div class="form-group">
<%= f.label :cover %>
<%= f.file_field :cover, class: 'form-control'%>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
So, in the show page of user add a link to settings page,
<%= link_to 'Edit', settings_path(user) %>
I am currently learning rails and I have the following code:
<%= form_for(#account) do |f| %>
<%= f.label :username %>
<%= f.text_field :username, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirm your password" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.label :website %>
<%= f.text_field :website, class: 'form-control' %>
<%= f.submit "Sign up!", class: "btn btn-primary" %>
<% end %>
I want to add glyphicons, so the code for one of the fields(:email) looks like so:
<div class="input-group">
<div class="input-group-addon">
<span class="glyphicon glyphicon-user"></span>
</div>
<%= f.email_field :email, class: 'form-control' %>
</div>
The trouble is, I want to do this for all the fields.
But then I'd have to copy-and-paste these same statements for all the fields, changing glyphicon-* and the field name (and field type for password fields). Is there a simpler DRY way to do this?
Alon Swain method is also correct, but I would suggest to use separate partial instead let say _input_field_password.html.erb
<div class="input-group">
<div class="input-group-addon">
<span class="glyphicon glyphicon-user"></span>
</div>
<%= f.email_field field_name, class: 'form-control' %>
</div>
Now change your form.erb
<%= form_for(#account) do |f| %>
<%= f.label :username %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :user_name}%>
<%= f.label :email %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :email} %>
<%= f.label :password %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :password}%>
<%= f.label :password_confirmation, "Confirm your password" %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :password_confirmation}%>
<%= f.label :website %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :website}%>
<%= f.submit "Sign up!", class: "btn btn-primary" %>
<% end %>
You could also refactor it further using loop
<%= form_for(#account) do |f| %>
<% [:username, :email, :password, :password_confirmation, :website].each do |field_name|
<%= f.label :field_name %>
<%= render partial 'input_field_password.html.erb', locals: {f: f, field_name: :field_name}%>
<%end%>
<%= f.submit "Sign up!", class: "btn btn-primary" %>
<% end %>
Kindly guide me to solve these errors in sign up and login views
<div class="jumbotronsignup">
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4 labelcolor">
<h3>SIGN UP</h3>
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, autofocus: true , class: 'form-control' %>
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off", class: 'form-control' %>
<%= f.label :password_confirmation, "Password Confirmation" %>
<%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control' %>
<div>
<%= f.label :is_female, "Gender" %>
<%= f.select :is_female, User::GENDER_TYPES , {}, { :class => 'form-control' } %>
</div>
<div>
<%= f.label :date_of_birth, :class=>'singleline' %>
<%= f.date_select :date_of_birth, { :start_year => 1920, :end_year => 2010 }, :class => 'form-control date-select datetest' %>
</div>
<div>
<%= f.label :avatar , "Profile Picture" %>
<%= f.file_field :avatar, accept: 'image/jpeg,image/gif,image/png,image/tiff', class: 'form-control' %>
</div>
<div class="row text-center">
<%= f.submit "Create my account", class: "btn mybtn-primary btn-lg" %>
</div>
<% end %>
</div>
</div>
</div><!-- end of container -->
</div><!-- end of jumbotron -->
How can I solve this error?
And this is my login page
<div class="jumbotronsignup">
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4 labelcolor">
<h3>LOG IN</h3>
<%= form_for(:session, url: login_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= link_to "(forgot password)", new_password_reset_path %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :remember_me, class: "checkbox inline" do %>
<%= f.check_box :remember_me %>
<span>Remember me on this computer</span>
<% end %>
<div class="row text-center">
<%= f.submit "Log in", class: "btn mybtn-primary btn-lg" %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
<% end %>
</div>
</div>
</div><!-- end of container -->
</div><!-- end of jumbotron -->