I am having trouble articulating the exact issue I am facing, but I will try with a brief descriptions and code.
I am trying to add a feature to a simple existing app that allows the user to crop an uploaded image for an avatar. I do the file selection on the same view that allows the user to update their password and other various account options. The user submits that form which then renders the view for the cropping feature. The issue is that from the crop view, the submission fails because it fails validation of parameters from the previous form. Basically I would like the form to all be submitted at the same time but from two different views.
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :avatar,
:crop_x, :crop_y, :crop_w, :crop_h
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
mount_uploader :avatar, AvatarUploader
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
after_update :crop_avatar
def crop_avatar
avatar.recreate_versions! if crop_x.present?
end
end
I have tried several different things to remedy this. I am sure I am missing a fundamental concept. Any ideas?
users_controller.rb
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
if params[:user][:avatar].present?
render 'crop'
else
sign_in #user
redirect_to #user, notice: "Successfully updated user."
end
else
render 'edit'
end
end
edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for #user, :html => {:multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :avatar %>
<%= f.file_field :avatar %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
crop.html.erb
<% provide(:title, 'Crop Avatar') %>
<h1>Crop Avatar</h1>
<div class="row">
<div class="span6 offset3">
<%= image_tag #user.avatar_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:100px; height:100px; overflow:hidden">
<%= image_tag #user.avatar.url(:large), :id => "preview" %>
</div>
<%= form_for #user do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
</div>
</div>
You can't have 2 views for one action. On a second thought why do you need it anyways, i mean you are rendering crop only when params[:user][:avatar] is present and that will be called only when you'll submit your edit.html.erb template. I think what you can do is have another method in controller with name crop and there update user's avatar with the dimention's specified.
Related
I am running a Rails 5.1 app with the following information:
Models
class Company < ApplicationRecord
has_many :complaints
accepts_nested_attributes_for :complaints
validates :name, presence: true
end
class Complaint < ApplicationRecord
belongs_to :company
validates :username, :priority, presence: true
end
Controller
class ComplaintController < ApplicationController
def new
#company = Company.new
#company.complaints.build
end
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
format.html { redirect_to complaint_url }
else
format.html { render :new }
end
end
end
private
def company_params
params.require(:company).permit(:name, complaints_attributes: [:username, :priority])
end
Form in view
<%= form_for #company do |f| %>
<%= f.label :name, "Company" %>
<%= f.text_field :name, type: "text" %>
<%= f.fields_for :complaints do |complaint| %>
<%= complaint.label :username, "Username" %>
<%= complaint.text_field :username %>
<%= complaint.label :priority, "Priority" %>
<%= complaint.text_field :priority %>
<% end %>
<%= f.submit 'Submit' %>
<% end %>
If I have just one input field for the complaint_attributes part of the form (in other words just one field for username and one field for priority as shown above), this works just fine.
However, if I want to have multiple fields for username/priority in the form, so that I can submit multiple username/priority combinations in a single submission, I find that submitting the form will only save the last username/priority values from the form. Example of this view would be:
<%= form_for #company do |f| %>
<%= f.label :name, "Company" %>
<%= f.text_field :name, type: "text" %>
<%= f.fields_for :complaints do |complaint| %>
<div>
<%= complaint.label :username, "Username" %>
<%= complaint.text_field :username %>
<%= complaint.label :priority, "Priority" %>
<%= complaint.text_field :priority %>
</div>
<div>
<%= complaint.label :username, "Username" %>
<%= complaint.text_field :username %>
<%= complaint.label :priority, "Priority" %>
<%= complaint.text_field :priority %>
</div>
<% end %>
<%= f.submit 'Submit' %>
<% end %>
I noticed that when submitting the form, I get a hash like this (for submitting single complaint):
{"utf8"=>"✓", "authenticity_token"=>"...", "company"=>{"name"=>"Test", "complaints_attributes"=>{"0"=>{"username"=>"test_person", "priority"=>"1"}}}, "commit"=>"Submit"}
Is there any way to modify the params to make it similar to this and have it saved to the DB?:
{"utf8"=>"✓", "authenticity_token"=>"...", "company"=>{"name"=>"Test", "complaints_attributes"=>{"0"=>{"username"=>"test_person", "priority"=>"1"}"1"=>{"username"=>"test_person", "priority"=>"2"}}}, "commit"=>"Submit"}
Or if not the above, what would be the best way to have the username/priority values saved if using multiple fields for them in a single form?
EDIT: I should point out that I can dynamically add the username/priority field groups as needed, so I don't want to be restricted to a set number.
the second block will override the first fields... you should instead build many complaints in the controller:
def new
#company = Company.new
3.times { #company.complaints.build }
end
and then with the following form it should generate to inputs according to the number of complaints you have built:
<%= form_for #company do |f| %>
<%= f.label :name, "Company" %>
<%= f.text_field :name, type: "text" %>
<%= f.fields_for :complaints do |complaint| %>
<%= complaint.label :username, "Username" %>
<%= complaint.text_field :username %>
<%= complaint.label :priority, "Priority" %>
<%= complaint.text_field :priority %>
<% end %>
<%= f.submit 'Submit' %>
<% end %>
I'm learning rails and building an authentication system using guides from around the web and following railscasts tutorials.
I've come to a stand still at the moment and need a bit of assistance if possible.
When ever I try to edit the user profile, I get an error message which tells me that it can't create an account due to fields such as email and username already being taken.
Looking around it seems it's related to how my edit form is being submitted, but I can't solve it!
Any help would be appreciated.
Users_controller.rb
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
edit.html.erb
<%= form_for :user, url: '/users' do |f| %>
<form class="m-t" role="form" action="#">
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control', autocomplete: "off" %>
</div>
<div class="form-group">
<%= f.label :user_type %>
<%= f.select(:user_type, ['Admin', 'Technical', 'Accounts'], {}, { :class => 'form-control' }) %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :telephone %>
<%= f.text_field :telephone, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :mobile %>
<%= f.text_field :mobile, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :user_name %>
<%= f.text_field :user_name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :company_admin%>
<%= f.check_box :company_admin, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :user_admin %>
<%= f.check_box :user_admin, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :emergency_contact %>
<%= f.check_box :emergency_contact, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.submit "Submit", class: "btn btn-primary block full-width m-b" %>
</div>
</form>
<% end %>
Rails Log
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'emailaddress#gmail.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."user_name" = 'AUserName' LIMIT 1
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :name, presence: { message: "Please enter your name." }
validates_uniqueness_of :email, presence: { message: "Please enter your email address." }
validates_format_of :email, with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z] {2,})\z/i, message: "Please enter a valid email address.", allow_blank: true
validates :telephone, presence: { message: "Please enter your phone number." }
validates :mobile, presence: { message: "Please enter your mobile number." }
validates_uniqueness_of :user_name, presence: { message: "Please enter your user name." }
validates_confirmation_of :password, presence: { message: "Please enter your password" }, allow_nil: true
before_create { generate_token(:auth_token) }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
end
Wait I'm wrong on the validation. Just spotted it.
<%= form_for :user, url: '/users' do |f| %>
This won't use the #user object, which means rails thinks you're trying to create a user.
Switch it to
<%= form_for #user do |f| %>
Rails will also infer the correct place to post to so you won't need the url option anymore.
So i am trying to implement a dropdown menu in my edit form for users, i used devise, so this edit form is inside my devise/registrations/edit.html.erb file.
first i get and error for undefined method for :optionselect (which seems understandable since i couldn't find this elsewhere other than this select in form_for rails
so this is wrong.
<div class="field">
<%= f.label :role %><br />
<%= f.select :optionselect, User.options %>
</div>
i also had it like this
<div class="field">
<%= f.label :role %><br />
<%= f.select :role, [['Member', 'member'], ['Astronaut', 'astronaut'], ['Candidate', 'candidate']] %>
but no luck. because it wouldn't persist the changes i made when editing the role of the user.
Also the name doesn't persist when trying to update it. maybe that gives us a lead.
models/user.rb
class User < ActiveRecord::Base
has_many :books
has_many :reviews
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable
validates :email, presence: true, uniqueness: true
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates :password,
:presence => { :on => :create },
:length => { :minimum => 6, :allow_nil => true }
OPTIONS = [
{:role => 'memeber'},
{:role => 'astronaut'},
{:role => 'candidate'}
]
def self.options
OPTIONS.map { |option| option[:role] }
end
end
controllers/users_controller.rb
class UsersController < ApplicationController
def index
binding.pry
#users = User.all
end
def show
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update!(user_params)
redirect_to :action => 'show', :id => #user
else
render :action => 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :role)
end
end
devise/registration/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
</div>
<div class="field">
<%= f.label :role %><br />
<%= f.select :optionselect, User.options %>
</div>
<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="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 %>
Let me know if you need more information
edit.html.erb
<%= f.select(:role, User::USER_OPTIONS) %>
models/user.rb
USER_OPTIONS = ["memeber", "astronaut", "candidate"]
I have implemented a user authentication system in rails using the gem 'bcrypt';I would like to insert a current password field to the edit form to make the changes to the password.
How can do this?
class User < ActiveRecord::Base
before_save { self.email = email.downcase}
before_create :create_remember_token
#Associations
has_one :profile
has_many :posts
#validations
validates :name, presence: true, length: {maximum: 50}
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
has_secure_password
validates :password, length: {minimum: 6}
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Thank you
In your view file:
<%= f.label :current_password %>
<%= f.password_field :current_password %>
Also make sure you permit the current_password parameter in your controller.
I assumed current_password attr is already defined by has_secured_password.
Ok I've searched far and wide and can't find a solution that I can get working...so I decided to post here.
I have 2 models
Store
class Store < ActiveRecord::Base
attr_accessible :storeimage, :storename
belongs_to :user
validates :user_id, :presence => true
end
and
User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation, :userimage, :remove_userimage
has_secure_password
has_many :gears
has_many :comments, :dependent => :destroy
has_one :store, :dependent => :destroy
before_save :create_remember_token
require 'carrierwave/orm/activerecord'
mount_uploader :userimage, UserpicUploader
accepts_nested_attributes_for :store
...
end
When someone creates a new user account I need to automatically create a new store for that user I was thinking within the user form. So how can I create a new store object that's linked to the new user being created?
Here is my code from the User Controller for CreateAction
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to #user, :flash => {:success => "Welcome to Equiptme"}
else
render 'new'
#title = "Sign up"
end
end
View
<div class="signup_container">
<div class="signup_container_interior">
<%= provide(:title, 'Sign up') %>
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div>
<div>
The form contains <%= pluralize(#user.errors.count, "error") %>.
</div>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :first_name %> <%= f.text_field :first_name, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :last_name %> <%= f.text_field :last_name, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :email %> <%= f.text_field :email, class: 'register_text_area' %>
</div>
</div>
<!--************STORE FIELDS ************** -->
<!--************STORE FIELDS END ************** -->
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :password %> <%= f.password_field :password, class: 'register_text_area' %>
</div>
</div>
<div class="register_field">
<div class="register_nonerror_container">
<%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'register_text_area' %>
</div>
</div>
<div class="actions">
<%= f.submit "Create Account", class: 'register_button' %>
</div>
<% end %>
</div>
</div>
You can use the build_association method created along with the has_one relationship between users and stores:
def create
#user = User.new(params[:user])
#user.build_store
# etc
end
If you don't need the store until you've saved the user, you might also use create_association:
if #user.save
#user.create_store
# etc
end
You may want to take a look at this:
http://railscasts.com/episodes/196-nested-model-form-part-1