Ruby on Rails - Does the scope of SessionsHelper reach models? - ruby-on-rails

In my Organisations module, I try to assign a value to a field before creating the Organisation record.
I use a before_create filter in the model, which usually works fine.
But when I try to assign a value coming from an attribute of the current_user method defined in the session, I get an Undefined method 'current_user' error message.
As doing this works fine in a controller, I wonder why it does not work in the model?
Here is my code for the model:
# == Schema Information
#
# Table name: organisations
#
# id :integer not null, primary key
# playground_id :integer
# code :string(255)
# name :string(255)
# description :text
# parent_organisation_id :integer
# organisation_level :integer
# hierarchy :string(255)
# created_by :string(255)
# updated_by :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Organisation < ActiveRecord::Base
### before filter
before_create :set_code
before_create :set_hierarchy
validates :code, presence: true, uniqueness: true
validates :name, presence: true, uniqueness: true
validates :organisation_level, presence: true
validates :created_by , presence: true
validates :updated_by, presence: true
# validates :owner_id, presence: true
# validates :status_id, presence: true
validates :playground_id, presence: true
# belongs_to :owner, :class_name => "User", :foreign_key => "owner_id" # helps retrieving the owner name
# belongs_to :status, :class_name => "Parameter", :foreign_key => "status_id" # helps retrieving the status name
belongs_to :organisation
has_many :organisations
### private functions definitions
private
### before filters
def set_code
if Organisation.count > 0
self.code = self.organisation.code + '-' + code
end
end
def set_hierarchy
if Organisation.count == 0
self.hierarchy = current_user.current_playground_id.to_s + '.001'
else
last_one = Organisation.maximum("hierarchy")
self.hierarchy = last_one.next
end
end
end
Here is my code for the SessionsHelper (inspired from Rails Tutorial):
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
Here is an example from a controller where the assignment works:
#business_flow.playground_id = current_user.current_playground_id
I'd be glad to understand why it does not work in the model.

The SessionsHelper module gets included into your controller class, so you can use its methods from there. It does not get included in the model class.
In fact it probably wouldn't work even if you included it by hand, because the model would need access to the cookies method for the current_user method to work. cookies comes from an ActionController method.
To achieve what you want, try making the change in your Organisation object from the controller that's creating that object, passing in the user information that the controller has access to.

Related

How to use Devise in models or use "if user_signed_in?" for associations?

Issue: I have a "belongs_to" association for a buyer.id but I also want people who aren't signed in to be able to create orders.
So I only need the association if the user is signed in
How can i do:
belongs_to :buyer, class_name: "User"
but have it only associate if a user is signed in.
I have tried:
belongs_to :buyer, class_name: "User", if: #user.current_user(true)
didn't work
belongs_to :buyer, class_name: "User", if: user_signed_in
def user_signed_in
#user.current_user(true)
end
didn't work
And a few other iterations of this.
I am using Devise and it seems as if it doesn't work in the models this way like it does in controllers.
In the controller, I have done this: (somewhat not relevant)
if user_signed_in?
#order.buyer_id = current_user.id
else
#order.buyer_id = nil
end
What can i do so the
belongs_to :buyer, class_name: "User"
only associates when a user is signed in?
My buyer_id migration:
class AddBuyerIdToOrders < ActiveRecord::Migration[5.2]
def change
add_column :orders, :buyer_id, :integer
end
end
Ended up finding a SO post about something similar that just used a guest_user.
This is the code I used - slightly/hardly altered:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
def current_or_guest_user
if current_user
if session[:guest_user_id] && session[:guest_user_id] != current_user.id
logging_in
# reload guest_user to prevent caching problems before destruction
guest_user(with_retry = false).try(:reload).try(:destroy)
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user(with_retry = true)
# Cache the value the first time it's gotten.
#cached_guest_user ||= User.find(session[:guest_user_id] ||= create_guest_user.id)
rescue ActiveRecord::RecordNotFound # if session[:guest_user_id] invalid
session[:guest_user_id] = nil
guest_user if with_retry
end
privte
def create_guest_user
u = User.new(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(100)}#example.com")
u.save!(:validate => false)
session[:guest_user_id] = u.id
u
end
Now no matter what, someone is a user even if a guest. And can create an account after an order with their orders listed if same email is used and email is confirmed.
You can't do it this way, because the model has no idea about signed_in status. If you want to create orders without users you should add optional: true to association, because Rails validates presence of belongs_to, starting from 5th version.
belongs_to :buyer, class_name: "User", optional: true

rails how to validatie data params in method dose not updated, created

I want to validate 1 params in model method, but i can't found any fit answers , please show me the right way.
class User < ActiveRecord::Base
validate :username, presence: true, length: 4..5, unique: true
validate :email, presence: true, unique: true, format: {with: /\A[a-z0-9\.]+#([a-z]{1,10}\.){1,2}[a-z]{2,4}\z/}
def self.get_post(id)
# how to call validate id ???
validates :id, numericality: true
if id.valid?
# true code
else
# false code
end
end
def change_profile
# How to check validate user and email
username.valid?
email.valid?
# some_code....
end
end
Thanks all.
You cannot use validates there, you can do this instead
def self.get_post(id)
if id.is_a? Numeric
# true code
else
# false code
end
end
You can use active model for your customization, you can not check validation on field to filed, but you can perform with active model with number of fields as per your requirement
http://railscasts.com/episodes/219-active-model
class User
include ActiveModel::Validations
validates_with UserProfile
end
class UserProfile < ActiveModel::Validator
def validate(record)
if some_complex_logic
record.errors[:base] = "This record is invalid"
end
end
private
def some_complex_logic
# ...
end
end

Saving model after updating an attribute

I have a variable in my model, remember_token, that is assigned a value and after that the model is successfully saved.
But with two other variables -- perishable_token and verified -- save doesn't pass database checks (I got rollbacks). So I used update_attribute.
I just tested assigning a value to remember_token and saving the model in rails console. save doesn't work here either. So I think the difference in before_save filters.
user.remember_token = "asdfa"
user.save
....
ROLLBACK
Although everything is working nice, I would be grateful if you could show me the reason behind this. Maybe there are other (better) ways?
Thanks in advance!
The following is my User model.
(I modeled email verification after AuthLogic examples, but not exactly. Also, credits to Mr Hartl's tutorial.)
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
# surname :string(255)
# remember_token :string(255)
# role :string(255)
# perishable_token :string(255)
# verified :boolean default(FALSE)
#
class User < ActiveRecord::Base
attr_accessible :email, :name, :surname, :password, :password_confirmation
# attr_reader :perishable_token
attr_protected :role #look at ROLES
has_secure_password
ROLES = %w[admin moderator editor author banned] << nil
has_many :courses
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
# before_save :generate_perishable_token
validates :name, presence: true, length: { maximum: 50 }
validates :surname, 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, length: { minimum: 6 } #, presence:true >>because there is password_digest
validates :password_confirmation, presence: true
validates :role, inclusion: { in: ROLES }
default_scope order: 'users.surname ASC'
def deliver_verification_instructions!
generate_perishable_token
Notifier.verify_email(self).deliver
end
def self.find_using_perishable_token(token,
age = KarvonSaroy::Application.config.PERISHABLE_TOKEN_VALID_FOR)
return if token.blank?
age = age.to_i
conditions_sql = "perishable_token = ?"
conditions_subs = [token]
if column_names.include?("updated_at") && age > 0
conditions_sql += " and updated_at > ?"
conditions_subs << age.seconds.ago
end
where(conditions_sql, *conditions_subs).first
end
def verify!
self.update_attribute(:verified, true)
# self.verified = true
# self.save
end
#used for sessions
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
def generate_perishable_token
# self.perishable_token = SecureRandom.urlsafe_base64
self.update_attribute(:perishable_token, SecureRandom.urlsafe_base64)
end
end
I would guess that the reason this is not saving properly is that this model you have created in the rails console fails the validations you have set.
The suggestion by gotva that you use save! is also a helpful one as this would show you whether this is the cause of the problem.

Create data in other tables when creating user

Good day.
I have 2 tables in my database (PostgeSQL): "Users" and "Folders". Folders are belongs_to :user and user has_many :folders. I need user, when creating his account automatically create one folder in folders table with name: "Default", id: 1, user_id: current_user.id. As I understand correctly, I need to edit create method in users_controller
This is my user.rb
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
# remember_token :string(255)
# admin :boolean default(FALSE)
#
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :folders, dependent: :destroy
before_save { 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, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
This is folder.rb
# == Schema Information
#
# Table name: folders
#
# id :integer not null, primary key
# name :string(255)
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Folder < ActiveRecord::Base
attr_accessible :name
belongs_to :user
has_many :bookmarks, dependent: :destroy
validates :user_id, presence: true
validates :name, presence: true
end
And this is the create method from users_controller.rb
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to #user
flash[:success] = "Welcome to Timio Bookmarks!"
else
if signed_in?
redirect_to root_path
else
render 'new'
end
end
end
Thanks for your help!
Try something like:
#user.folders << Folder.new
before you do the save on the #user.save

Limit the number of rows of a column a user has based on parameter

I'm building a call-tracking application as a way to learn rails and twilio.
Right now, I have the model scheme plans has_many users has_many phones.
In the plans model, I have a parameter called max_phone_numbers.
What I'd like to do is to limit the number of phones a user has based on the max_phone_numbers the plan gives.
The flow looks something like this :
1) User buys a bunch of phone numbers
2)When User.phones.count = max_phone numbers, then ability to buy more phone numbers is disabled, and a link pops up to the upgrade_path
I'm not quite sure how I would go about doing this though. What are the combinations of things I would need to do in my model, and in my controller?
What would I define in my controller, in such a way that in the view I can warp if/then statements around the buttons?
i.e if limit is reached, than show this, else show button
What would I put in my models to prevent someone from just visiting the link instead?
Any guidance, or resources on doing something like this would be greatly appreciated
Here's my current user model
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
# remember_token :string(255)
# twilio_account_sid :string(255)
# twilio_auth_token :string(255)
# plan_id :integer
# stripe_customer_token :string(255)
#
# Twilio authentication credentials
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :plan_id, :stripe_card_token
has_secure_password
belongs_to :plan
has_many :phones, dependent: :destroy
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: true
validates :password, presence: true, length: { minimum: 6 }, on: :create
validates :password_confirmation, presence: true, on: :create
validates_presence_of :plan_id
attr_accessor :stripe_card_token
def save_with_payment
if valid?
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
def create_twilio_subaccount
#client = Twilio::REST::Client.new(TWILIO_PARENT_ACCOUNT_SID, TWILIO_PARENT_ACCOUNT_TOKEN)
#subaccount = #client.accounts.create({:FriendlyName => self[:email]})
self.twilio_account_sid = #subaccount.sid
self.twilio_auth_token = #subaccount.auth_token
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
You could add a custom validation to your Phone model to check if a user has reached their limit. That would prevent any new Phone's from being created if the user has reached their limit.
In your User class
def at_max_phone_limit?
self.phones.count >= self.plan.max_phone_numbers
end
In your Phone class
validate :check_phone_limit, :on => :create
def check_phone_limit
if User.find(self.user_id).at_max_phone_limit?
self.errors[:base] << "Cannot add any more phones"
end
end
In your view/form, you would do something like this
<% if #user.at_max_phone_limit? %>
<%= link_to "Upgrade your Plan", upgrade_plan_path %>
<% else %>
# Render form/widget/control for adding a phone number
<% end %>

Resources