I'm having an issue with my user registration form in Ruby on Rails.
I had it working before simply with just a username, email, and password. However when I tried to add fields for first name, last name, and ZIP code, it stopped inserting any data into the database, and just redirects back to the registration form.
I did it the correct way with generating migrations and migrating the db- the form still wasn't working.
I then dropped the database entirely and recreated it with all of the fields included, and it still won't work. The database was generated correctly with the correct fields, and I'm not sure where the disconnect is.
I'm using ruby 2.3.1.
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/home'
else
redirect_to '/register'
end
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :location, :fname, :lname)
end
end
User model:
class User < ApplicationRecord
has_secure_password
end
Form at users/new:
<div class="container">
</div>
<div id="contact" class="container-fluid bg-grey">
<h2 class="text-center">Create An Account</h2>
<form>
<%= form_for(#user) do |f| %>
<%= f.text_field :username, :placeholder => "Username" %>
<%= f.email_field :email, :placeholder => "Email" %>
<%= f.password_field :password, :placeholder => "Password" %><br/><br/>
<%= f.text_field :fname, :placeholder => "First Name" %>
<%= f.text_field :lname, :placeholder => "Last Name" %>
<%= f.number_field :location, :placeholder => "ZIP Code (US Only)" %><br/><br/>
<%= f.submit "Create an Account", class: "btn-submit" %>
<% end %>
</div>
</ul>
</nav>
</body>
</html>
Create users migration:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :password_digest
t.numeric :location
t.string :fname
t.string :lname
t.timestamps
end
end
end
From log:
Started GET "/register?utf8=%E2%9C%93&authenticity_token=b6M1gpQx8BTLhBqjjh6R%2BlSGghcSh18Mg7eGskLGNyq11RBvGCX%2BOJjVhSLwwRmZunn1sYvV4MGHB7vrJw6Rhg%3D%3D&user%5Busername%5D=jsmith1&user%5Bemail%5D=jsmith%40email.com&user%5Bpassword%5D=[FILTERED]&user%5Bfname%5D=John&user%5Blname%5D=Smith&user%5Blocation%5D=60606&commit=Create+an+Account" for ::1 at 2016-11-07 15:14:50 -0600
Processing by UsersController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"b6M1gpQx8BTLhBqjjh6R+lSGghcSh18Mg7eGskLGNyq11RBvGCX+OJjVhSLwwRmZunn1sYvV4MGHB7vrJw6Rhg==", "user"=>{"username"=>"jsmith1", "email"=>"jsmith#email.com", "password"=>"[FILTERED]", "fname"=>"John", "lname"=>"Smith", "location"=>"60606"}, "commit"=>"Create an Account"}
Rendering users/new.html.erb within layouts/application
Rendered users/new.html.erb within layouts/application (2.0ms)
Completed 200 OK in 195ms (Views: 148.1ms | ActiveRecord: 21.5ms)
)
Completed 200 OK in 760ms (Views: 714.8ms | ActiveRecord: 3.5ms)
Thank you so much for any help.
I figured it out. The extra form tag was messing with the form submission. Once I removed <form> from above the Ruby form code, it worked. Thank you to the people who responded.
Related
What I'm trying to accomplish:
When a user registers with my app they are taken to a new account creation page. This is where they enter their desired subdomain. from this form I also want to create the owner (a user class).
The problem:
As it sits right now, when i fill out the generated form (below)
<%= form_for #account do |f| %>
<%= fields_for :owner do |o| %>
<p>
<%= o.label :f_name %>
<%= o.text_field :f_name %>
</p>
<p>
<%= o.label :m_name %>
<%= o.text_field :m_name %>
</p>
<p>
<%= o.label :l_name %>
<%= o.text_field :l_name %>
</p>
<p>
<%= o.label :email %>
<%= o.email_field :email %>
</p>
<p>
<%= o.label :password %>
<%= o.password_field :password %>
</p>
<p>
<%= o.label :password_confirmation %>
<%= o.password_field :password_confirmation %>
</p>
<% end %>
<p>
<%= f.label :subdomain %>
<%= f.text_field :subdomain %>
</p>
<%= f.submit %>
<% end %>
and try to submit the form, I get the following rails server output:
Started POST "/accounts" for 127.0.0.1 at 2018-04-08 21:52:57 -0600
Processing by AccountsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"4yUhk6N40udNBMoBJz/sFzbjC/RUtU7FVyHe9NlhtBkmpGEMZE0+xMcD7E6GLOjgp02hbkrbuMNLQ5gBjh+kvA==", "owner"=>{"f_name"=>"xxxxx", "m_name"=>"xxxxx", "l_name"=>"xxxxx", "email"=>"xxxxx#xxxxxnltd.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "account"=>{"subdomain"=>"testinga"}, "commit"=>"Create Account"}
(0.2ms) BEGIN
Account Exists (0.6ms) SELECT 1 AS one FROM "accounts" WHERE LOWER("accounts"."subdomain") = LOWER($1) LIMIT $2 [["subdomain", "testinga"], ["LIMIT", 1]]
(0.1ms) ROLLBACK
Rendering accounts/new.html.erb within layouts/application
Rendered accounts/new.html.erb within layouts/application (2.4ms)
Completed 200 OK in 49ms (Views: 21.5ms | ActiveRecord: 8.3ms)
Now when I read the output I cant seem to find why this is rolling back and not saving. I do see it telling me an account already exists whit that subdomain, however this is a CLEAN database and there are no accounts saved in it! When I run byebug just before the #account.save in the accounts controller (below) there are no error messages or details I can find.
My AccountController: (I've left the byebug in the controller, perhaps im putting it in the wrong place?)
class AccountsController < ApplicationController
def index
end
def show
end
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
byebug
if #account.save
redirect_to root_path, notice: 'Account creates successfully.'
else
render action: 'new'
end
end
def edit
end
def update
end
def destroy
end
private
def account_params
params.require(:account).permit(:subdomain, :owner_id, :plan_id, :account_verified, :account_status, owner_attributes: [:id, :email, :password, :password_confirmation, :f_name, :m_name, :l_name, :office_country_code, :office_phone_number, :mobile_country_code, :mobile_phone_number])
end
end
My Account model
class Account < ApplicationRecord
RESTRICTED_SUBDOMAINS = %w(www admin loadlead)
belongs_to :owner, class_name: 'User'
has_many :users
validates :owner, presence: true
validates :subdomain, presence: true,
#uniqueness: { case_sensitive: false },
format: { with: /\A[\w\-]+\Z/i, message: 'contains invalid characters'},
exclusion: { in: RESTRICTED_SUBDOMAINS, message: 'restricted name'}
before_validation :downcase_subdomain
accepts_nested_attributes_for :owner
protected
def downcase_subdomain
self.subdomain = subdomain.try(:downcase)
end
end
My User model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
belongs_to :account
end
Any assistance here would be greatly appreciated! I have no idea where I'm going wrong with this? Thanks in advance.
Try to call fields_for on f builder instead:
<%= form_for #account do |f| %>
<%= f.fields_for :owner do |o| %>
<p>
<%= o.label :f_name %>
<%= o.text_field :f_name %>
</p>
# ....
<% end %>
# ....
<%= f.submit %>
<% end %>
And you can remove :owner_id, this attribute value will be set automatically by Rails when we're using :accepts_nested_attributes_for.
You are calling #account.save which does not raise an exception. It returns true if everything is fine, or returns false when the validation fails (if #account.valid? returns false).
If there are any validation errors, you can check them by calling:
pry(main)> #account.valid?
pry(main)> false
pry(main)> #account.errors
That should help you debug the issue.
I'm working on a blog website written in RoR and got stuck on a problem with Sorcery. I did the tutorial from their documentation to create the simple login. My problem is, that they use email to identify the user at the login.
So I tried to modify my session controller to send the username as parameter instead of email and modified my view accordingly.
The log says that everything works fine and the username and password is passed to the database. But, and I can't find a solution to that, the SQL string that's generated still uses "authors"."email" as parameter.
How can I fix that?
My log:
Processing by AuthorSessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ForXjJMiPCI6H37xqtPzGwa9XBOHx1yIaGjlZdUd6Iw+G4M5v6s/JXrFcGG5VVyuFl6Is+cr5Zp/fxJcNyS/Tw==", "username"=>"Test", "password"=>"[FILTERED]", "commit"=>"Login"}
Author Load (0.5ms) SELECT "authors".* FROM "authors" WHERE "authors"."email" = 'Test' ORDER BY "authors"."id" ASC LIMIT ? [["LIMIT", 1]]
Rendering author_sessions/new.html.erb within layouts/application
Rendered author_sessions/new.html.erb within layouts/application (2.4ms)
Completed 200 OK in 63ms (Views: 49.6ms | ActiveRecord: 2.5ms)
My session controller:
class AuthorSessionsController < ApplicationController
def new
end
def create
if login(params[:username], params[:password])
redirect_back_or_to(articles_path, notice: 'Logged in successfully.')
else
flash.alert = 'Login failed.'
render action: :new
end
end
def destroy
logout
redirect_to(articles_path, notice: 'Logged out!')
end
end
My new.html.erb
<h1>Login</h1>
<%= form_tag author_sessions_path, method: :post do %>
<div class="field">
<%= label_tag :username %>
<%= text_field_tag :username %>
<br>
</div>
<div class="field">
<%= label_tag :password %>
<%= password_field_tag :password %>
<br>
</div>
<div class="actions">
<%= submit_tag 'Login' %>
</div>
<% end %>
<%= link_to 'Back', articles_path %>
I did encounter the same problem, and the following helped:
- when installing sorcery (rails g sorcery:install) in the migration file change the :email to :username so it would look like this
class SorceryCore < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :username, :null => false
t.string :crypted_password
t.string :salt
t.timestamps :null => false
end
add_index :users, :username, unique: true
end
end
then rake db:migrate so I had a user model
I saw you made the users_sessions already, so lets skip the rails generate controller UserSessions new create destroy and populating the views part
in my users_sessions_controller.rb file at the create action I also call login(params[:username], params[:password]), which is a sorcery method and by default it takes :email as a username_attribute
to change that to :username, I went to the /config/initializers/sorcery.rb and found a config.user_config do |user| line (around line 188), and added user.username_attribute_names = [:username] to it, so instead of the email, it would take username.
This solved it for me. Don't forget to change the :email to :username everywhere you use it.
The attachment resume seems to works fine, but i do not have any insert into database (null, null, null , null) and i do not have file uploaded to any folder in my app...
class AddAttachmentCvToUsers < ActiveRecord::Migration
def change
change_table :users do |t|
t.attachment :cv
end
end
end
User model :
attr_accessor :cv
validates_attachment :cv
has_attached_file :cv, :path=>":rails_root/storage/#{Rails.env}#{ENV['RAILS_TEST_NUMBER']}/."
I have also installed carrierwave but still no effects..
Edit:
User Controller (I do not have another controller for attachments) :
class UsersController < ApplicationController
def new
#users = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
current_user = #user.id
redirect_to '/status'
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :PESEL, :phone, :password,:cv)
end
end
View for new user with attachement:
<div class="login">
<div class="container">
<div class="form">
<h1>SIGN UP</h1>
<%= form_for #users,:html=> {:multipart=>true} do |f| %>
<%= f.text_field :first_name, :placeholder => "First name" %>
<%= f.text_field :last_name, :placeholder => "Last name" %>
<%= f.email_field :email, :placeholder => "Email" %>
<%= f.text_field :PESEL, :placeholder => "PESEL number" %>
<%= f.phone_field :phone, :placeholder => "Phone Number" %>
<%= f.password_field :password, :placeholder => "Password" %>
<p>CV</p>
<%= f.file_field :cv, name: "CV", class: 'form-control' %>
<%= f.submit "Sign up", class: "btn-submit" %>
<% end %>
</div>
</div>
</div>
Some logs from console:
Started POST "/users" for 127.0.0.1 at 2016-05-18 03:55:17 +0200
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Fw6easThY51CDppDDVfqO0ProQITaltqP3DaIL3An67ey4vGXh2yEerhhhxoo3bTp/mKbkIaAmktzBviBIjg8g==", "user"=>{"first_name"=>"Test", "last_name"=>"Test", "email"=>"test#t.pl", "PESEL"=>"91020300441", "phone"=>"609123123", "password"=>"[FILTERED]"}, "CV"=>#<ActionDispatch::Http::UploadedFile:0x007f25790c1b60 #tempfile=#<Tempfile:/tmp/RackMultipart20160518-26849-rqaabr.pdf>, #original_filename="pdf-test.pdf", #content_type="application/pdf", #headers="Content-Disposition: form-data; name=\"CV\"; filename=\"pdf-test.pdf\"\r\nContent-Type: application/pdf\r\n">, "commit"=>"Sign up"}
(0.1ms) BEGIN
User Exists (1.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'test#t.pl' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM `users` WHERE `users`.`PESEL` = BINARY '91020300441' LIMIT 1
SQL (0.1ms) INSERT INTO `users` (`first_name`, `last_name`, `email`, `PESEL`, `phone`, `password_digest`, `created_at`, `updated_at`) VALUES ('Test', 'Test', 'test#t.pl', '91020300441', '609123123', '$2a$10$HmHAiJkHv1Tada/OpzKXKOISiwumoFKTy48tFpNBYuATq/A5GaC9G', '2016-05-18 01:55:17', '2016-05-18 01:55:17')
SQL (1.0ms) INSERT INTO `job_apps` (`user_id`, `created_at`, `updated_at`) VALUES (35, '2016-05-18 01:55:17', '2016-05-18 01:55:17')
(3.0ms) COMMIT
Redirected to http://localhost:3000/status
Completed 302 Found in 135ms (ActiveRecord: 8.2ms)
Started GET "/status" for 127.0.0.1 at 2016-05-18 03:55:17 +0200
Processing by JobAppsController#index as HTML
You have overridden the name attribute of the file_field, which has broken Rails naming conventions. If you remove the name attribute, Rails will be able to pass the file details uploaded in the :cv field to the database.
Change the file_field to this:
<%= f.file_field :cv, class: 'form-control' %>
If you have Javascript attached to the form, and need to refer to the file_field element, you can use this, instead:
<%= f.file_field :cv, id: "cv", class: "form-control" %>
I'm implementing an invitation system and I want the new user form to pre-populate the user's email address in the email address field on the form (eventually, I will refactor this so it's not a form_field), so that the user doesn't have to type in all their information, just enter a password.
I have created the getter/setter methods in the users.rb model like this:
def invitation_token
invitation.invitation_token if invitation
end
def invitation_token=(invitation_token)
self.invitation = Invitation.find_by_invitation_token(invitation_token)
end
INVITATION MODEL
class Invitation < ActiveRecord::Base
#--== ASSOCIATIONS
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'
#--== CALLBACKS
before_create :generate_token
before_create :recipient_is_not_registered
before_create :decrement_sender_count, :if => :sender
#--== VALIDATIONS
validates_presence_of :recipient_email
#validate :recipient_is_not_registered
validate :sender_has_invitations, :if => :sender
#--== METHODS
private
def recipient_is_not_registered
if User.find_by_email(recipient_email)
false
else
true
end
end
def sender_has_invitations
unless sender.invitation_limit > 0
redirect_to root_url
end
end
def generate_token #TODO: MOVE to lib/generate_token.rb
self.invitation_token = Digest::SHA1.hexdigest([Time.now, rand].join)
end
def decrement_sender_count
sender.decrement! :invitation_limit
end
end
USER CONTROLLER
class UsersController < ApplicationController
def new
#user = User.new(:invitation_token => params[:invitation_token])
#user.email = #user.invitation.recipient_email if #user.invitation
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
...
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :admin)
end
end
views/users/_form.html.erb
<%= form_for #user do |f| %>
<%= f.hidden_field :invitation_token %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.check_box :admin %>
<%= f.label :admin %>
</div>
<div class="actions"><%= f.submit %></div>
<% end %>
I was following Ryan Bates' RC#124 - Beta Invitations, and got stuck here. His code doesn't produce the error, so I should mention that this is a Rails 3.2.18 app.
When I reload the form, the user's email isn't populated in the form. The relevant log shows:
Started GET "/signup.914823d28d07b747213ec3de47f89ad537169e34" for 127.0.0.1
at 2016-04-30 20:24:47 -0600
Processing by UsersController#new as
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."auth_token" = 'rOHiKmDcceytxi_t151YIQ' LIMIT 1
Invitation Load (0.0ms) SELECT "invitations".* FROM "invitations" WHERE "invitations"."invitation_token" IS NULL LIMIT 1
Rendered users/_form.html.erb (5.0ms)
Rendered users/new.html.erb within layouts/application (6.0ms)
Completed 200 OK in 102.0ms (Views: 25.0ms | ActiveRecord: 3.0ms)
So it appears that the invitation_token isn't being passed in, since the log shows it is NULL.
I have gone over the RC code from top to bottom and can't find out why it's not being passed.
Any help would be appreciated. Thanks.
UPDATE: The output from the view source is:
<input id="user_invitation_token" name="user[invitation_token]" type="hidden" />, so it's not being passed along.
Set the value on the hidden field by passing the value: key:
<%= f.hidden_field :invitation_token, value: some_value %>
When I try to create a user in my dashboard app, nothing really happens. The page refreshes else, render 'new' due to failure I think. I don't get any errors, but my user is not getting created. I do get this info in the log though, it appers that it is trying to create the user. How can I trouble shoot sqlite to see why the user is not being created?
Started POST "/dashboard_users_index" for 172.16.1.29 at 2014-02-16 13:09:50 -0500
Processing by DashboardUsersController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"M9wVDyde4qbYzl517BwMTAqEti0Ju2WtrhX1bh1UGS4=", "dashboard_users"=>{"email"=>"my_user#domain.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create Dashboard users"}
Geokit is using the domain: logmon
Rendered dashboard_users/new.html.erb within layouts/application (4.7ms)
Completed 200 OK in 28ms (Views: 27.6ms | ActiveRecord: 0.0ms)
Dashboard Users Controller:
class DashboardUsersController < ApplicationController
def new
#dashboard_user = DashboardUsers.new
end
def create
#dashboard_user = DashboardUsers.new(params[:dashboard_user])
if #dashboard_user.save
redirect_to 'csdashboard/index', :notice => 'Signed up!'
else
render 'new'
end
end
end
Dashboard Users Model:
class DashboardUsers < ActiveRecord::Base
attr_accessible :email, :password_hash, :password_salt
attr_accessor :password
validates :password, :presence => true,
:confirmation => true
validates :email, :presence => true,
:uniqueness => true
before_save :encrypt_password
def self.authenticate(email, password)
dashboard_user = find_by_email(email)
if dashboard_user && dashboard_user.password_hash == BCrypt::Engine.hash_secret(password, dashboard_user.password_salt)
dashboard_user
else
nil?
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash =BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
Dashboard Users /new.html.rb:
<h1>Create a user</h1>
<%= form_for #dashboard_user do |f|%>
<% if #dashboard_user.errors.any? %>
<div class="alert-error">
<h2>Form is invalid</h2>
<ul>
<% for message in #dashboard_user.full_message %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_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>
<p class='button'><%= f.submit %></p>
<% end %>
Also, here is my schema.rb
ActiveRecord::Schema.define(:version => 20140215195045) do
create_table "dashboard_users", :force => true do |t|
t.string "email"
t.string "password_hash"
t.string "password_salt"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
You don't need to debug the connection between Rails and SQLite. You can either print a log or much better to insert a breakpoint to debug your code.
I recommend you to use a powerful debugger like PRY
https://github.com/pry/pry
You can put a debug breakpoint binding.pry to see what is happening
def create
#dashboard_user = DashboardUsers.new(params[:dashboard_user])
binding.pry
if #dashboard_user.save
redirect_to 'csdashboard/index', :notice => 'Signed up!'
else
render 'new'
end
end
Then when making a POST to this action, the executing will stop in this breakpoint, and you can see what is going on with the #dashboard_users
> #dashboard_users.save! # with the ! will show the error
> #dashboard_users.valid? # false
> #dashboard_users.errors # returns the errors
> #dashboard_users.errors.full_messages # errors in a clear text
> etc...
Model names are singular .
Change the class name to DashboardUser like
class DashboardUser < ActiveRecord::Base
and the file name should be dashboard_user.rb insted of dashboard_users.rb
The table name should be plural like dashboard_users
In your controller change
def new
#dashboard_user = DashboardUser.new
end
def create
#dashboard_user = DashboardUser.new(dashboard_user_params)
if #dashboard_user.save
redirect_to dashboard_path , :notice => 'Signed up!'
else
render 'new'
end
end
Is it intentional that you named the model DashboardUsers?
Either try renaming everything in the app from "DashboardUsers" into "DashboardUser".
The resource is called dashboard_users but the model is singular.
Or try at first if it works if you apply the naming convention to this line:
class DashboardUsersController < ApplicationController
def new
#dashboard_user = DashboardUsers.new
end
def create
# here is a typo, in the params hash in the log the name is different
#dashboard_user = DashboardUsers.new(params[:dashboard_users])
if #dashboard_user.save
redirect_to 'csdashboard/index', :notice => 'Signed up!'
else
render 'new'
end
end
end
But in general. At first try to apply the Rails way as recommended in the RailsGuides or any other Rails Tutorial Resource/ Book.