Rails 4, not saving #user.save when registering new user - ruby-on-rails-4

When I try to register an user, it does not give me any error but just cannot save the user.
I don't have attr_accessible. I'm not sure what I am missing. Please help me.
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :email, presence: true,
uniqueness: true,
format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
validates :password, presence: true, length: {minimum: 6}
validates :nickname, presence: true, uniqueness: true
end
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params) # Not saving #user ...
if #user.save
flash[:success] = "Successfully registered"
redirect_to videos_path
else
flash[:error] = "Cannot create an user, check the input and try again"
render :new
end
end
private
def user_params
params.require(:user).permit(:email, :password, :nickname)
end
end
Log:
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x5OqMgarqMFj17dVSuA8tVueg1dncS3YtkCfMzMpOUE=", "user"=>{"email"=>"example#example.com", "password"=>"[FILTERED]", "nickname"=>"example"}, "commit"=>"Register"}
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'example#example.com' LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."nickname" = 'example' LIMIT 1
(0.1ms) rollback transaction

Regarding our short discussion in the comments, it appears that one or two things are happening to cause #user.save to return false:
One of the validation rules are failing
A callback within your model is returning false, thus halting processing and rolling back the transaction
There are a few quick ways to debug the validations. I figured I could describe them so you could learn a few options.
A. Change the call within the if statement to instead use the bang method of save:
if #user.save!
This will cause the app to raise an exception if validation fails, displaying the validation errors within the browser on your screen. In this particular scenario, you'd want to remember to remove the ! after you're done debugging because you probably don't want the final version of your app doing that.
Or...
B. Within the else statement, add this line:
raise #user.errors.to_yaml
This will display the validation errors within the browser on the screen. Of course, remember to remove this line after you're done debugging.
Or...
C. Within the else statement, add this line and then run the form post:
puts #user.errors.to_yaml
This will display the validation errors within your console. You'll want to remember to remove this line after you're done debugging, but it's "less worse" if you happen to forget because at least the extra info is only output to STDOUT.
You may want to try each of these just to get a little practice and to see what your options are in simple debugging scenarios like this.

High chances that error is in password confirmation. You use has_secure_password from Rails, which automagically handles password confirmation for you. And here is the problem - you don't have it before user creation. Thus just add. For details check out similar question on has_secure_password
And check, that you have password_digest:string in users table :)

Related

Assign nested attributes records to current user when using Cocoon gem

In my application I have models Post & Slides & I have:
class Post < ActiveRecord::Base
has_many :slides, inverse_of: :post
accepts_nested_attributes_for :slides, reject_if: :all_blank, allow_destroy: true
Everything works fine, only thing I need (because of how my application will work), is when a slide is created, I need to assign it to current_user or user that is creating the record.
I already have user_id in my slides table and:
class User < ActiveRecord::Base
has_many :posts
has_many :slide
end
class Slide < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
My PostsController looks like this:
def new
#post = current_user.posts.build
// This is for adding a slide without user needing to click on link_to_add_association when they enter new page/action
#post.slides.build
end
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Was successfully created.' }
else
format.html { render :new }
end
end
end
Any help is appreciated!
There are two ways to accomplish this:
First option: when saving the slide, fill in the user-id, but this will get pretty messy quickly. You either do it in the model in a before_save, but how do you know the current-user-id? Or do it in the controller and change the user-id if not set before saving/after saving.
There is, however, an easier option :) Using the :wrap_object option of the link_to_add_association (see doc) you can prefill the user_id in the form! So something like:
= link_to_add_association ('add slide', #form_obj, :slides,
wrap_object: Proc.new {|slide| slide.user_id = current_user.id; slide })
To be completely correct, you would also have to change your new method as follows
#post.slides.build(user_id: current_user.id)
Then of course, we have to add the user_id to the form, as a hidden field, so it is sent back to the controller, and do not forget to fix your strong parameters clause to allow setting the user_id as well :)
When I'm looking at this I see three ways to go about it, but since you're on cocoon already, I would drop the connection between user & slides - as it kind of violates good database practices (until you hit a point where you page is so popular you have to optimize of course, but that would be done differently).
You are using cocoon, but you're not utilizing the nesting of the relationship fully yet ...
The best practice would be to have cocoon's nesting create both & instead of trying to assign to current_user you call something like:
#slides = current_user.posts.find_first(param[:id]).slides
The #slides saves all the results, the .Post.find(param[:id]) finds a specific post for current_user.
Note: this is not the most optimized way & I haven't tested this, but it shows you the format of one way you can think about the relationships. You will need to hit rails console and run some tests like ...
(rails console)> #user = User.first
Next we test that there are posts available, as it's frustrating to test blanks & not get the results ...
(rails console)> #posts = #user.posts
Then we use the find method & I'm going to use Post.first just to get a working id, you can easily put "1" or any number you know is valid ...
(rails console)> #post = #posts.find(Post.first)
Finally, we go with either all slides to make sure its a valid dataset
(rails console)> #post.slides
If you want a specific slide later & have a has_many relationship just tag that find method on the .slides after.
Also one last thing - when you state earlier in there you need the current_user to be related, you can use an entry in your model.rb to create a method or a scope to get the data & allow you to link it to the current_user more easily & even drop some directed SQL query with the .where method to pull that information up if performance is an issue.
I spotted a second optimization in there ... if everything really is working - don't worry about this!
And don't forget about the strong_parameters nesting to do this fully ... Strong Param white listing
Basic format ... `.permit(:id, :something, slide_attributes: [:id, :name, :whatever, :_destroy])

Activerecord uniqueness validation ruby on rails 4.2

I just started trying my hands on Ruby on rails . i have created a mode states and want that every state name must remain unique so i used
uniqueness: true
as per http://guides.rubyonrails.org/active_record_validations.html .
As the above document says that the validation is invoked automatically when object.save is called. but When i try to save the objects with same state_name value , no exception is thrown and the record is saved. Can one please help where i am doing it wrong.
Model code
class State < ActiveRecord::Base
acts_as_paranoid
validates_presence_of :state_name ,uniqueness: true
end
Controller code
def create
#stateName = params[:stateName];
#state = State.new();
#state.state_name=#stateName;
if(#state.save())
resp = { :message => "success" }
else
resp = { :message => "fail" }
end
respond_to do |format|
format.json { render :json => resp }
end
end
Thanks in advance for helping!
If you want uniqueness check, change
validates_presence_of :state_name ,uniqueness: true
to
validates :state_name, uniqueness: true
If you want uniqueness and presence check both, use
validates :state_name, uniqueness: true, presence: true
An alternate syntax is shown below, however, syntax shown above should be preferred
validates_uniqueness_of :fname
validates_presence_of :fname
Also, as per documentation, please note following with respect to usage of uniqueness: true
It does not create a uniqueness constraint in the database, so it may
happen that two different database connections create two records with
the same value for a column that you intend to be unique. To avoid
that, you must create a unique index on both columns in your database.
The validation happens by performing an SQL query into the model's
table, searching for an existing record with the same value in that
attribute.
What this means is that it is possible that if multiple users are trying to save records concurrently, there is a possibility records with duplicate state_name can get created as each save is happening on different thread

Rails 4 Devise Not Logging In

I have a rails 4 app that uses devise for user authentication. Everything was working beautifully until I decided to add an "admin" parameter to the "Devise::User" model. I added it and created a custom User Controller to alloy my forms to update the fields. After I did this, I added more attributes. This is where my app started misbehaving. When I try to access an area with before_action :authenticate_user!, I get sent to the sign in page, implying that I'm not signed in. When I put in a users credentials and hit submit, I get sent to the root_path of the app with no notification of a successful (or failed) login instead of where I was going. When I try to go back to the restricted area (now that I'm "signed in") I get redirected to the sign in page again.
After reviewing all this, it seemed to me that devise is not actually logging in, so I added a log_out button to my home page to see if I could log out. When I click it, my logs say Filter chain halted as :verify_signed_out_user rendered or redirected. I'm not sure if that's normal or not (since I can't check now).
I'm at a complete loss as to where to go from here. I'm still a bit of a rails noob so it's possible the solution is staring me in the face.
Here's my routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
resources :musics, :composers, :music, :welcome, :charges, :tracks, :books
root 'welcome#index'
get 'admin' => 'welcome#admin'
get 'admin/music/:id/tracks' => 'welcome#tracks', as: :admintracks
end
And RegistrationsController.rb
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :admin, :fname, :lname, :company, :address1, :address2, :city, :state, :zip, :phone)
end
def account_update_params
params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :admin, :fname, :lname, :company, :address1, :address2, :city, :state, :zip, :phone)
end
end
I appreciate all the help.
EDIT 1:
I confirmed that it is not logging in by placing a <% if current_user %>Logged In<% end %> line on my root_page. After logging in through the form, it still doesn't display. I then checked my logs to see what it gave for that log in and I don't spot anything fishy.
Started POST "/users/sign_in" for ::1 at 2015-12-13 21:16:47 -0500
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"HgStdwJajEbJMKyBgSGTD7Omqvdw9g6gmZwbXEmGd4VRFJqcLlrzjDYAdAWo7VdhpXm7sbNbuFTcR6neJTVr/g==", "user"=>{"email"=>"[*MyEmail*]#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "[*MyEmail*]#gmail.com"]]
(0.1ms) BEGIN
SQL (0.3ms) UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5 [["last_sign_in_at", "2015-12-14 02:13:31.458050"], ["current_sign_in_at", "2015-12-14 02:16:47.893957"], ["sign_in_count", 27], ["updated_at", "2015-12-14 02:16:47.896163"], ["id", 1]]
(1.1ms) COMMIT
Redirected to http://localhost:3000/
After related question jumping on here, I discovered an (unaccepted) answer to a related issue that solved my problem! In a previous attempt at something last night, I had messed with the session store domain and apparently just hadn't used anything relating to Devise since. Maybe this will help someone else!
Thanks, #amit_saxena

Rspec/Capybara: Devise user 'dissapears' after logging in

I'm having a bizarre problem where I create an admin user for an Rspec/Capybara test and the user is mysteriously deleted after logging in. When I run my test, the user is created and successfully logged in. However when Capybara visits the admin_categories_path, the test fails. Rails raises an exception because current_user is not defined. When I insert a binding.pry, I can see that the user exists up until they are logged in, at which point the user disappears from the test database, causing current_user to be undefined, and thereby triggering an exception. I'm at a loss as to how/why this is happening.
UPDATE: I've gotten past the problem of the user being deleted. Now when Capybara sees the admin_categories_path page, category isn't displayed. Inserting a binding.pry reveals that category is present in the database.
When I launch the app and log in manually, I have no problems accessing admin_categories_path.
Here is my spec file:
require 'rails_helper'
feature 'admin edits category', %Q{
As an admin, I want to edit a category or subcategory, so that it better
represents the content under it.
Acceptance Criteria:
* [X] - I can edit the name of a category inline.
* [X] - I can edit the name of a subcategory inline.
} do
let(:admin) do
FactoryGirl.create(:user, admin: true)
end
let(:category) do
FactoryGirl.create(:category)
end
scenario 'admin edits category title', js: true, focus: true do
login_as(admin)
visit admin_categories_path
bip_area category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
end
Here is my helper file authentication.rd:
module Helpers
module Authentication
def log_in_as(user)
visit new_user_session_path
within "#new_user" do
fill_in 'user[email]', with: user.email
fill_in 'user[password]', with: user.password
click_on "Log in"
end
end
end
RSpec.configure do |config|
config.include Authentication, :type => :feature
end
end
Here is my user factory:
require 'factory_girl'
FactoryGirl.define do
factory :user do
sequence(:email) {|n| "lafiel.abriel#{n}#abhnation.com" }
username
password 'password'
password_confirmation 'password'
end
factory :category do
sequence(:name) { |n| "Category ##{n}" }
parent_id nil
display_index 1
user
end
sequence :username do |n|
"Lafiel_Abriel_#{n}"
end
end
And here is my application_controller.rd where the exception is triggered:
module Admin
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :reject_unless_admin
layout 'admin/layouts/application'
protect_from_forgery with: :exception
helper :avatar, :devise, :admin
protected
def reject_unless_admin
unless current_user && current_user.admin?
raise ActionController::RoutingError.new('404: Not Found')
end
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [
:avatar,
:remote_avatar_url,
:email,
:username,
:first_name,
:last_name,
:age,
:website,
:password,
:password_confirmation,
:current_password
]
end
end
end
Any help/insight is greatly appreciated. Thanks.
If I recall correctly, this problem had something to do with the test database schema being out of sync with the development database. Try running rake db:test:prepare to ensure your test schema matches your development schema.
In my specific case, I had a two problems to overcome.
The first problem occurred when I created a category and an admin in a let block. Those needed to be placed in a before block so that they were created before the test executed. When I placed those variables in let blocks, they were not being created until the first time they were called in the test. So when I logged in as an admin, the admin variable was being passed to my login_as helper method before it was saved to the database. The same is true for the category variable.
This code doesn't work for me:
let(:admin) do
FactoryGirl.create(:user, admin: true)
end
let(:category) do
FactoryGirl.create(:category)
end
scenario 'admin edits category title', js: true, focus: true do
login_as(admin)
visit admin_categories_path
bip_area category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
This is solution I used to overcome the first problem:
before(:each) do
#admin = FactoryGirl.create(:user, admin: true)
#category = FactoryGirl.create(:category, user: #admin)
end
scenario 'admin edits category title', js: true do
skip "Doesn't work yet."
login_as(#admin)
visit admin_categories_path
wait_for_ajax
bip_text #category, :name, 'Test Category'
expect(page).to have_content 'Test Category'
end
The second problem is that when my test hits the admin/categories_controller.rb, Category.all returns an empty array, even though #category.save! and #category.valid? return true when I test my before block. I was never able to find a solution to the problem and ended up putting the test on ice.
I think part of the problem is that the documentation for the Best-in-Place gem is not very good. I used it at the time because it was an easy solution to my problem. Going forward though, I would use something like angular for this use-case. The documentation is much better and it's not a black box like a lot of gems are.
I'm not sure what bip_area does, but since your test says that it's editing a category I assume you are expecting the category to be present on the page when you visit admin_categories_path. When you visit that path however category has not yet been created since you are using 'let' which is lazily evaluated (created at time of first use of the variable), so it would not be shown on the screen for you to edit. Using binding.pry and then looking at that variable would actually create it, so it might be confusing you into thinking it was there. You can use 'let!' instead which will force the variable to be created before each test instead of lazily evaluating it.

Rails 4.0.4: How do I display whether or not the creation of a record was successful?

So After submitting a form for my Testimony model I get the following activity in my rails console:
Processing by TestimoniesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Y7n/+rlDoH3ys68HMOh6T6WFpAelRT18WUPstCz41vE=", "testimony"=>{"first_name"=>"bob ", "last_name"=>"balaban", "email"=>"", "contact_number"=>"", "country"=>"", "question1"=>"", "question2"=>"", "question3"=>"", "question4"=>"", "question5"=>"", "signature"=>"", "waiver"=>"0"}, "commit"=>"Save Testimony"}
(0.1ms) begin transaction
Testimony Exists (0.2ms) SELECT 1 AS one FROM "testimonies" WHERE ("testimonies"."last_name" = 'balaban' AND "testimonies"."first_name" = 'bob ' AND "testimonies"."email" = '') LIMIT 1
(0.1ms) rollback
Here is TestimoniesController
class TestimoniesController < ApplicationController
def new
end
def index
end
def show
#testimony = Testimony.find(params[:id])
end
def create
#testimony = Testimony.new(post_params)
#testimony.save
redirect_to #testimony
end
private
def post_params
params.require(:testimony).permit(:first_name, :email, :last_name, :contact_number, :country, :question1, :question2, :question3, :question4, :question5, :signature, :waiver)
end
end
Here is my Model file for Testimony.rb
class Testimony < ActiveRecord::Base
validates_presence_of :first_name, :last_name,:email, :contact_number, :country, :question1, :question2, :question3, :question4, :question5, :signature, :waiver
validates_uniqueness_of :last_name, :scope => [:first_name, :email]
end
I would like to display a message such as:
Record already exists
Or
All the fields need to be filled out
I realize this is pretty pathetic but I thought it was part of Rails magic to assert the uniqueness and presence of all of the fields of a Model at the form level, before you perform a #modelname.save. I clearly don't really understand. Thanks for your help.
if #modelname.save! failed it'll raise an exception... the exception name varies depending on the orm you might be using. but most likely it'll be ActiveModel::Validations
you can use the following pattern i myself use
#testimony.save!
redirect_to #testimony
rescue_from ActiveModel::Validations do |ex|
# here you can flash the message do what ever you want when saving fails
render json: {message: 'Record already exists', status: :unprocessable_entity
end
other solution is to use the following
if #testimony.save
redirect_to #testimony
else
render json: {message: 'Record already exists', status: :unprocessable_entity
end
[EXTRA INFO YOU CAN IGNORE :D]
I use the first solution cause i can handle exceptions in the application_controller.
for example you can add those to the application_controller to handle those failing cases
rescue_from CanCan::AccessDenied, with: :render_access_denied
rescue_from Mongoid::Errors::DocumentNotFound, with: :render_not_found
rescue_from ActionController::RoutingError, with: :render_not_found
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
error = {}
error[parameter_missing_exception.param] = ['parameter is required']
render_bad_request error
end
where render_XXX are methods defined in the application controller.