cant sort active records - ruby-on-rails

I am a noobie and I am trying to simply get all the records in the database and display them in alphabetical order. Whenever I display the index page the records are always sorted in descending by their id. I used the console to try calling EvalTest.order("name") and again I kept getting the records sorted by their id in descending order instead of by name. Do I need to add an index on the name column to sort by it? This seems like the answer should be so easy but I can't seem to figure it out...
Here is my code:
User Model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :eval_tests
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
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
after_validation { self.errors.messages.delete(:password_digest) }
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Eval_Test Model:
class EvalTest < ActiveRecord::Base
attr_accessible :description, :name
belongs_to :user
validates :user_id, presence: true
validates :name, presence: true
validates :description, presence: true, length: { maximum: 350 }
default_scope order: 'eval_tests.created_at DESC'
end
EvalTest Controller:
class EvalTestsController < ApplicationController
def show
#eval_test = EvalTest.find(params[:id])
end
def new
#eval_test = EvalTest.new
end
def index
#eval_tests = EvalTest.order("name")
end
def create
#eval_test = current_user.eval_tests.build(params[:eval_test])
if #eval_test.save
flash[:success] = "Nouveau test cree!"
redirect_to #eval_test
else
render 'new'
end
end
end
Evaluation Test index.html.erb:
<% provide(:title, 'Index des tests') %>
<h1>Index des tests</h1>
<ul class="eval_tests">
<% #eval_tests.each do |eval_test| %>
<li>
<%= link_to eval_test.name, eval_test %>
</li>
<% end %>
</ul>

This is happening because you have used default scope in your model. Try
#eval_tests = EvalTest.reorder("name")
This should solve your issue.

Related

impossible to encrypt a password in a multi-step form with bcrypt

I'm a beginner in ruby on rails and I have a problem encrypting a password in my registration form. I installed the bcrypt gem but I don't understand why the form doesn't work...
my form model :
module Wizard
module User
STEPS = %w(step1 step2 step3).freeze
class Base
include ActiveModel::Model
include ActiveModel::SecurePassword
attr_accessor :user
has_secure_password
delegate *::User.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :user
def initialize(user_attributes)
#user = ::User.new(user_attributes)
end
end
class Step1 < Base
validates :firstName, presence: {
message: 'Un prénom doit être renseigné'
}, length: { maximum: 50,
too_long: '50 caractères maximum pour le prénom' }
validates :lastName, presence: {
message: 'Un nom doit être renseigné'
}, length: { maximum: 50,
too_long: '50 caractères maximum pour le nom' }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255,
too_long: '255 caractères maximum pour l\'adresse mail' },
format: { with: VALID_EMAIL_REGEX,
message: 'Vous devez saisir une adresse mail valide' }
end
class Step2 < Step1
validates :password, presence: true, length: { in: 8..15 }, length: { in: 8..15 }
end
class Step3 < Step2
validates :school, presence: true
validates :typeOfTeacher, presence: true
validates :yearsOfExperience, presence: true
end
end
end
My model User.rb :
class User < ApplicationRecord
validates :firstName, presence: true, length: { maximum: 50 }
validates :lastName, 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: true
has_secure_password
validates :password, presence: true
validates :school, presence: true
validates :typeOfTeacher, presence: true
validates :yearsOfExperience, presence: true
end
My controller :
When saving the user in my create function. The registration stops because of the password. I think I'm using wrong has_secure_password.
class WizardsController < ApplicationController
before_action :load_user_wizard, except: %i(validate_step)
def validate_step
current_step = params[:current_step]
#user_wizard = wizard_user_for_step(current_step)
#user_wizard.user.attributes = user_wizard_params
session[:user_attributes] = #user_wizard.user.attributes
if #user_wizard.valid?
next_step = wizard_user_next_step(current_step)
create and return unless next_step
redirect_to action: next_step
else
render current_step
end
end
def create
if #user_wizard.user.save
session[:user_attributes] = nil
redirect_to letsgo_path
else
redirect_to({ action: Wizard::User::STEPS.first } )
end
end
private
def load_user_wizard
#user_wizard = wizard_user_for_step(action_name)
end
def wizard_user_next_step(step)
Wizard::User::STEPS[Wizard::User::STEPS.index(step) + 1]
end
def wizard_user_for_step(step)
raise InvalidStep unless step.in?(Wizard::User::STEPS)
"Wizard::User::#{step.camelize}".constantize.new(session[:user_attributes])
end
def user_wizard_params
params.require(:user_wizard).permit(:firstName, :lastName, :email, :password, :password_confirmation, :school, :typeOfTeacher, :yearsOfExperience)
end
class InvalidStep < StandardError; end
end
My view :
<div class="div_Signup">
<div class="div_SignupBlock">
<%= render 'navbarSignup' %>
<div class="div_SignupBlockInt">
<div class="div_SignupText">
Inscription
</div>
<div class="div_SignupTextName">
Choisissez un mot de passe
</div>
<div class="div_SignupForm">
<%= form_for #user_wizard, as: :user_wizard, url: validate_step_wizard_path do |f| %>
<%= hidden_field_tag :current_step, 'step2' %>
<div class="div_SignupInputPassword">
<%= f.password_field :password, placeholder: 'Mot de passe', :class => field_class(#user_wizard, :password) %>
<% #user_wizard.errors[:password].each do |message| %>
<p style="color: red;"><%= message %></p>
<% end %>
</div>
<div class="div_SignupInputPasswordConfirmation">
<%= f.password_field :password_confirmation, placeholder: 'Confirmation du mot de passe', class: 'input_Signup' %>
</div>
</div>
<%= f.submit 'Suivant', class: 'button_Signup' %>
<% end %>
</div>
<footer class="footer_Signup">
<%= render 'footerSignup2' %>
</footer>
</div>
</div>
When I test my form when entering a password, I get error messages that show that the password cannot be empty, and the password confirmation field does not work.
However, I see that the password has been encrypted.
Thanks !!!

Rails NoMethodError for method I did not call

I'm getting the following error
Error Message Image
When trying to save a message object in my MessageController. Here is my controller.
class MessagesController < ApplicationController
def new
#message = Message.new
#user = current_user
end
def create
#message = Message.new(message_params)
#message.user = current_user
#message.user_id = current_user.id
if #message.user_email.nil?
#message.user_email = current_user.email
end
if #message.save
# UserMailer.send_email_to_admin(current_user.email).deliver
else
# redirect_to new_message_path(#message)
end
end
private
def message_params
params.require(:message).permit(:subject, :body, :user_email)
end
end
And here is my model.
class Message < ActiveRecord::Base
belongs_to :user
validates :user_email, presence: true
validates :subject, presence: true, length: { minimum: 5 }
validates :message, presence: true, length: { minimum: 10 }
end
I have no idea why this error is appearing because there are no methods named "message" in my app. Any help would be much appreciated!
In your model you have a validation for the message field:
validates :message, presence: true, length: {minimum: 10}
Is that supposed to be a validation for your body field?:
validates :body, presence: true, length: {minimum: 10}
Before saving the record, the validator is calling the message method on the Message instance(#message) to check its presence and validate it. Since you don't have a column named message but have a validation for it, you will get the NoMethodError.

Validation doesn't work as expected for related models in Rails 4?

I use one form to enter data for two models. When I save parent model (Tenant) the child model (User) also gets saved, but only if I don't validate tenant_id in User model. If I do validates :tenant_id, presence: true in User model then validation error "Users tenant can't be blank" is displayed. Any ideas why?
Tenant model:
class Tenant < ActiveRecord::Base
has_many :users, dependent: :destroy, inverse_of: :tenant
accepts_nested_attributes_for :users
before_validation do
self.status = 0
self.name = name_orig.upcase
email.downcase!
end
validates :name_orig, presence: true, length: { maximum: 255 }
validates :name, uniqueness: { case_sensitive: false }
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 }
validates :status, presence: true
end
User model:
class User < ActiveRecord::Base
belongs_to :tenant, inverse_of: :users
validates_presence_of :tenant
before_validation do
self.status = 0
self.email = email.downcase
end
VALID_USERNAME_REGEX = /\A\w+\s?\w*\z/i
validates :name, presence: true, length: { maximum: 50 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
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, presence: true, length: { minimum: 6 }
validates :tenant_id, presence: true
validates :status, presence: true
end
Tenant controller:
class TenantsController < ApplicationController
def new
#tenant = Tenant.new
#tenant.users.build
end
def create
#tenant = Tenant.new(tenant_params)
#tenant.save
if #tenant.save
flash[:success] = "Welcome!"
redirect_to #tenant # redirects to tenant profile
else
render 'new'
end
end
private
def tenant_params
params.require(:tenant).permit(:name_orig, :email,
users_attributes: [:name, :email, :password, :password_confirmation])
end
end
Signup form:
<%= form_for(#tenant) do |f| %>
<%= render 'shared/tenant_error_messages' %>
<%= f.label :name_orig, "Company name" %>
<%= f.text_field :name_orig, class: 'form-control' %>
<%= f.label :email, "Company e-mail" %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.fields_for(:users) do |u| %>
<%= u.label :name, "User name" %>
<%= u.text_field :name, class: 'form-control' %>
<%= u.label :email, "User e-mail" %>
<%= u.email_field :email, class: 'form-control' %>
<%= u.label :password, "Password" %>
<%= u.password_field :password, class: 'form-control' %>
<%= u.label :password_confirmation, "Password confirmation" %>
<%= u.password_field :password_confirmation, class: 'form-control' %>
<% end %>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
Since you are using nested attributes and saving both models at the same time, you cannot validate tenant_id for user since they will be persisted in a transaction.
Because tenant is not persisted, it does not yet have an id. Since it does not have an id, there cannot be tenant_id for user.
In this case validating tenant_id is pointless, because you cannot persist a user without tenant since user is being built on top of tenant. So if your user will be persisted, then a corresponding tenant will also be present.
In the case you mentioned, where users can sign up on an independent form -
To validate that a tenant will be associated in the create action use:
tenant = Tenant.find_by(params[:tenant_id])
user = tenant.users.build(user_params)
instead of
user = User.new(user_params)
This way you will not have any orphan children

to_param not working in nested polymorphic associated model

This test is failing at the line get_users_path:
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
#admin = users(:user_baz)
end
test "index as admin including pagination and delete links" do
log_in_as(#admin)
get users_path
.
.
end
end
Here is the error message:
ActionView::Template::Error: undefined method 'callsign' for nil:NilClass
app/models/user.rb:35:in 'to_param'
app/views/users/_user.html.erb:3:in '_app_views_users__user_html_erb___623096829469928541_2227766840'
app/views/users/index.html.erb:8:in '_app_views_users_index_html_erb__62429272046032246_2224894860'
test/integration/users_index_test.rb:9:in `block in <class:UsersIndexTest>'`
It's referring to the line self.character.callsign in the to_param method in the User model.
User.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
has_one :character, as: :sociable, dependent: :destroy
accepts_nested_attributes_for :character
has_secure_password
before_validation do
self.create_character unless character
end
before_save do
self.email.downcase!
end
before_create :create_activation_digest
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,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }, allow_blank: true
validates :character, presence: true
def to_param
self.character.callsign
end
.
.
end
Character.rb:
class Character < ActiveRecord::Base
belongs_to :sociable, polymorphic: true
before_save do
self.callsign.downcase!
end
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
end
app/views/users/index.html.erb:
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<%= render #users %>
</ul>
<%= will_paginate %>
app/views/users/_user.html.erb:
<li>
<%= gravatar_for_user user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>
Why is this test failing? Why is self.character.callsign in to_param not working?
It was because I hadn't manually given a character to all the users in test/fixtures. In characters.yml I created a character for every user, and the test passed.

Rails Change record values

I have a record in postgresql of user status it is boolean and its attributes are "true" and "false". I want to show "true" as "active and "false" as "inactive". How do I do it with query or any thing to add in model.
Controller:
def index
#users = User.reorder("id ASC").page(params[:page]).per_page(10)
#count = 0
end
Model:
class User < ActiveRecord::Base
has_many :orders
has_many :order_statuses
attr_accessible :first_name, :last_name, :email, :password,
:password_confirmation, :code
validates :first_name, presence: true
validates :last_name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6}
has_secure_password
before_save { self.email = email.downcase }
before_create :create_remember_token
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
Add this method in your model, and when you call #user.status, it will show 'Active' or "Inactive".
def status
self.status? ? "Active" : "Inactive"
end
Hope, It will help. Thanks
If I understand you correctly you want to display to your users "active" instead of true and "inactive" instead of false.
You could do something like this in all your views:
#user.status? ? 'active' : 'inactive'
Or if you need this in a bunch of places you could write a helper:
module UserHelper
def status_text(user)
#user.status? ? 'active' : 'inactive'
end
end
# and call it from your views like this:
<%= status_text(#user) %>
Or you could put that into a model method if you need this function only in conjunction with the user and it's active method (as per Rails Guy's suggestion)
Lastly you could use I18n to translate the string for you if you have a mulitlingual page:
# en.yml
en:
status:
true: 'active'
false: 'inactive'
# user_helper.rb
def status_text(user)
I18n.t("statys.#{user.status.to_s}")
end

Resources