I have a user table, after the user is created I want to edit one attribute using the below code. This is my user edit view:
<h1>Please select below</h1>
<%= form_for #user do |f| %>
<div class="form-group">
<%= f.label :extra_activity %>
<%= f.select(:extra_activity, [['P_Act', 1],['Ph_Act', 2], ['C_Act', 3]], class: 'form-control', required: true) %></br>
</div>
<%= f.submit 'Submit', class: 'btn btn-primary btn-lg' %>
<% end %>
In my user controller I have the following methods for edit and update :
def edit
#user = User.find(params[:id])
#users = User.all
#user_id = params[:user_id]
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to new_user_activity_path(#user)
else
redirect_to home_path
end
end
user_params are listed below:
def user_params
params.require(:user).permit(:first_name, :surname, :previous_award, :chosen_award, :email, :password, :password_confirmation, :extra_activity)
end
When i initially create the user, :extra_activity is set to 0. When the user clicks submit on the edit form, nothing happens, the user is redirected to home_path. I just need to update the user's :extra_activity attribute to whatever they select in the form. Can anybody suggest where I am going wrong here? Not sure how to save the selected number, as the updated value for :extra_activity
UPDATE:
class User < ActiveRecord::Base
has_many :activities, dependent: :destroy
has_many :weeks, dependent: :destroy
authenticates_with_sorcery!
validates :password, length: { minimum: 3 }
validates :password, confirmation: true
validates :email, uniqueness: true, email_format: { message: 'has invalid format' }
end
After reading your comments and checking the update, i guess the solution is to add:
validates :password, length: { minimum: 3 }, if: :password
The password is most likely stored in hashed form and not in password column. So if you reload the user the attribute is not set.
The validation should be: IF the password is set, then make sure that it is at least of length 3 (which is pretty short).
You should make sure that the password that is stored is not changed when you update the user through this controller.
Related
So I'm creating a simple app for myself and a small group of people. I would like to restrict access to people that I hand-generate codes for by typing them in myself.
User sign up, log in, logout works, but I don't just want anyone to be able to be register.
TL;DR
User can sign up but how do I go about setting up a hand-generated code
Should be some way to invalidate that code after sign up and see who
the code is associated with
How can I do this in rails?
I know the user_model would have to add some sort of field to it, the view/form for it as well, and it would have to be validated (by the controller?). Just stuck.
My thought process is as follows (what i've thought so far)
All the invite codes should be kept as an array in a file in the
rails app?
I will have to add a migration that adds invite_code to the model/db/view form
The controller should validate the presence of the invite code in the view form?
user/new.html.erb
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Retype Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create My Account" %>
<% end %>
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome!"
redirect_to #user
# Handle a successful save.
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
user.rb model
class User < ActiveRecord::Base
# links this to the question.rb model
has_many :questions, dependent: :destroy
attr_accessor :remember_token
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# returns a random token
def User.new_token
SecureRandom.urlsafe_base64
end
# remembers a user in the database for use in persistent sessions
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# returns true if the given token matches the digest
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
end
Well, In that case, you can have a model say Token created as below:
def self.up
create_table :tokens do |t
t.string :code, null: false
t.boolean :used, default: false
t.timestamps
end
end
And a migration in your User table for token_id
You can generate new code like, Token.generate_new_code
def self.generate_new_code
token = Token.new(code: Digest::SHA1.hexdigest Time.now.to_s)
token.code if token.save
end
And you can understand the rest i.e. accept code from registration form, validate for unused code and set it true and token_id if the registration is successful.
I use sorcery for user authentication in a rails 4.1 application. Everything works fine. But when I try to update specific attributes of the user model (which is authenticated by sorcery), I get an error that the password is blank and is too short.
Here's a snippet from the console
> user = User.last
=> # I get the user
> user.update(about_me: "I'm a user")
=> false
> user.update(about_me: "I'm a user", password: "secret")
=> true
Here's my model code
app/models/user.rb
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :password, presence: true, length: { minimum: 6 }
.....
end
My controller code
app/controllers/users_controller.rb
class UsersController < ApplicationController
.....
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to #user
flash[:notice] = "Profile successfully updated"
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:username, :name, :email, :password, :about_me)
end
end
And my update form
app/views/users/edit.html.erb
<%= form_for #user, method: :put do |f| %>
<% if #user.errors.any? %>
<div class="alert">
<p><%= pluralize(#user.errors.count, 'error') %></p>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field :username, placeholder: 'Username' %>
<%= f.text_field :name, placeholder: 'Name' %>
<%= f.email_field :email, placeholder: 'Email' %>
<%= f.text_area :about_me, placeholder: 'About me' %>
<%= f.password_field :password, placeholder: 'Password' %>
<%= f.submit 'Save Changes', class: 'button' %>
<% end %>
If I remove the password field from the form, I get errors about the password being blank and about it's length.
Is this something to do with sorcery or is it something I'm missing with rails itself?
Is there a better way to update let's say only the email field without affecting anything else?
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :password, presence: true, length: { minimum: 6 }, if: :new_user?
private
def new_user?
new_record?
end
end
The validation will be checked only if it's a new_record, for which we have added our own private validation method new_user?. This function will return true during your normal signups/registrations. Hence, at those signups only the password validation will be needed.
During the edit, off course the user will be an existing user / new_record? will return false. Hence the validation for password will be skipped.
2nd way:
class User < ActiveRecord::Base
attr_accessor :skip_password
validates :password, presence: true, length: { minimum: 6 }, unless: :skip_password
end
#users_controller.rb
def update
#user = User.find(params[:id])
#user.skip_password = true
if #user.update(user_params)
redirect_to #user
else
render 'edit'
end
end
Here we have added our own custom attr_accessor skip_password. If the skip_password value is set to true, then during edit/update the password validation will be skipped.
I hope both of those ways will help you :)
If someone looks for this topic in future, it is possible to use changes map of ActiveRecord model:
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :password, presence: true, length: { minimum: 6 }, if: -> {new_record? || changes[:crypted_password]}
.....
end
where :crypted_password is the value of sorcery_config.crypted_password_attribute_name.
Also currently such condition of validates pointed in Simple Password Authentication sorcery wiki article.
I'm building off the tutorial app in ruby on rails for a project, and I'm trying to create an association between two models.
In my database, there are users, events, and an attendance table that associates with the email from a user and a code from an event.
I've tried to research how to do this myself, but every time I try to validate the attendance email to a user, it states that the user cannot be blank as if I were trying to create a new one.
Still quite new to Ruby on Rails, so any advice would be appreciated! The models are below.
User Model:
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
has_many :attendances, inverse_of: :user
accepts_nested_attributes_for :attendances
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates(:name, presence: true, length: { maximum: 50 })
validates(:email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false})
validates(:password, length: { minimum: 6 } )
validates(:password_confirmation, presence: true)
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Attendance Model:
class Attendance < ActiveRecord::Base
attr_accessible :code, :email
belongs_to :user
validates_presence_of :user
end
So far I'm only trying to enforce the association between User and Attendance, once I get that working I'll do the same to Events. Also, this is Rails 3.2.19 and Ruby 1.9.3.
EDIT: Here is the code I'm using for the form, I believe that it works because until I put the validation into the model it was creating rows into the Attendance table.
<% provide(:title, 'Test Event') %>
<h1>Attendance Registration</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#attendance) do |f| %>
<%= render 'shared/attendance_error_messages' %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :code %>
<%= f.text_field :code %>
<%= f.submit "Submit", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Also, here's the attendance controller, if that helps.
class AttendancesController < ApplicationController
def new
#attendance = Attendance.new
end
def create
#attendance = Attendance.new(params[:attendance])
if #attendance.save
flash[:success] = "Attendance logged."
redirect_to root_path
else
render 'new'
end
end
end
Add this line to your form to avoid the user presence error
<%= f.hidden_field :user_id, current_user.id %>
I have
Model
class User < ActiveRecord::Base
attr_accessible :email
validates :email,
presence: true
serialize :data, ActiveRecord::Coders::Hstore
%w[zipcode first_name].each do |key|
attr_accessible key
define_method(key) do
data && data[key]
end
define_method("#{key}=") do |value|
self.data = (data || {}).merge(key => value)
end
end
end
Controller
class UsersController < ApplicationController
def create
#user = User.find_or_initialize_by_email(params[:user][:email])
if #user.update_attributes(params[:user])
redirect_to :back, notice: "Thanks for sign up!"
else
render "pages/home"
end
end
end
View with client side validation
<%= simple_form_for User.new, validate: true do |f| %>
<%= f.input :email %>
<%= f.input :first_name %>
<%= f.input :zipcode %>
<%= f.button :submit, 'Sign up' %>
<% end %>
First question: I would like to update existing user record but not if param is "" or " ", how to achieve this?
Second question: Should I use create action to do that? Maybe update will be more clear. But this form also create an user object.
Third question: Is any chance to add uniqueness validation to email attribute? Right now my client-side validation do not allow do that.
First: To disallow updating a field with empty strings, set allow_blank: false you could also do allow_nil: false. Add these to your validations in your model.
Second: N/A
Third: Simply add uniqueness: true to your email validation in your model.
Read more here
I have a Developer model that :has_one User model. This allows for authentication and stuff across different user types.
When I create a new Developer with incorrect User data, it renders the list of validation errors. When I update a Developer with incorrect User data, it just re-renders the edit form (as it should) but doesn't show the validation errors.
My validation error display code sits in my fields partial for the form so that shouldn't make a difference.
I feel like the issue is in the way I'm trying to update my models.
def update
#developer = Developer.find(params[:id])
if #developer.user.update_attributes(params[:user]) && #developer.update_attributes(params[:developer])
flash[:success] = "Profile Updated"
sign_in #developer.user
redirect_to #developer
else
render 'edit'
end
end
and my User validations aren't anything fancy:
validates :name, presence: true, length: {maximum: 30}
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, length: {minimum: 6}
validates :password_confirmation, presence: true
I've read at least 10 different similar-sounding posts but I haven't found anything that's helped. Any help would be great.
Edit
When I submit my update form, the following params come through
Parameters: {"utf8"=>"✓", "authenticity_token"=>"70xmNVxxES7lK2bSIIul/i5GaiJhB9+B5bV/bUVFlTs=", "user"=>{"name"=>"foo", "email"=>"foo#example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "developer"=>{"skype_name"=>""}, "commit"=>"Save changes", "id"=>"11"}
It still doesn't do the User validations. If I do the following via the console, it works though (i.e. it saves when the params are good and fails when the params are bad):
Developer.last.update_attributes(:user_attributes => {:name => "test updated", :email => "test#example.com", :password => "123456", :password_confirmation => "123456"})
So the only thing that seems different to me is the :user_attributes rather than just :user that my form is giving me. How do I change that?
Edit 2
Relevant part of my _fields partial for the form:
<%= render 'shared/error_messages' %>
<%= fields_for :user do |user| %>
<%= user.label :name %>
<%= user.text_field :name %>
<%= user.label :email %>
<%= user.text_field :email %>
<%= user.label :password %>
<%= user.password_field :password %>
<%= user.label :password_confirmation, "Confirm Password" %>
<%= user.password_field :password_confirmation %>
<% end %>
and my Developer#edit action:
def edit
#developer = Developer.find(params[:id])
end
No need to save user and developer separately, you can manage to save the user through developer model like this,
<%= form_for(#developer) do |f| %>
... developer's attribute ...
<%= f.fields_for :user do |ff| %>
... user's attribute ...
in controller, only
#developer = Developer.find(params[:id])
if #developer.update_attributes(params[:developer])
....
In developer model, you just need to add,
accepts_nested_attributes_for :user
and
attr_accessible :user_attribute
now form_for will automatically display the validation errors of user's model as well.
see this link for more details http://rubysource.com/complex-rails-forms-with-nested-attributes/