Rails Devise limit user sign up per ip - ruby-on-rails

I'd like to limit user sign up per IP to 3!
In User model I have:
class User < ApplicationRecord
validate :validate_ip
def validate_ip
errors[:username] << "My error description" if User.where(last_sign_in_ip: last_sign_in_ip).count > 3
end
end
I do know the problem in this line User.where(last_sign_in_ip: last_sign_in_ip)
"last_sign_in_ip" is empty. That's why my condition doesn't work. I need somehow get IP address of user inside the model.
Any advice how I can achieve it?

You need to pass the ip variable from controller. Model cannot access request variables and on signup devise do not update last_sign_in_ip or last_sign_in_ip so they are null. They are set up only on login.
In your controller before creating the user object pass the ip value as instance variable
#remote_ip = request.remote_ip
And then in your model use the code below:
class User < ApplicationRecord
validate :validate_ip
def validate_ip
errors[:username] << "My error description" if check_multiple_sign_ups
end
def check_multiple_sign_ups
recent_user_count = User.where(last_sign_in_ip: #remote_ip ).count
(recent_user_count > 3 ) ? false : true
end
end
Hope this Helps...

Related

How to insert ip address in active admin?

I have a model called booking and I am using active admin plugin as a resource management. I have a form called booking in the backend in which I need to insert ip address and username of the currently logged in user(who insert the form data) to the database without making any input field in backend. Please suggest. I am using mysql as database platform.
here is my controller syntax
class CustomizedBookingsController < ApplicationController
def create
customized_booking = CustomizedBooking.new(params[:customized_booking])
customized_booking.booked_by = current_admin_user
customized_booking.booking_ip = request.remote_ip
end
end
I tried lots but still not working.
If you're using Devise for authentication, you can use the method current_user, see the documentation here: https://github.com/plataformatec/devise#controller-filters-and-helpers
To add the IP address, you have the ip method, part of the ActionDispatch::Request. Check the documentation here: http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-ip
So if your booking model has both user and ip fields/methods, you can set them in the create action in your BookingsController
def create
booking = Booking.new(booking_params)
booking.user = current_user
booking.ip = request.ip
end

Modify attribute value based on user role

I have a column 'created_by' in a table. Based on the role of logged in user I have to show either the id of the user or the role of the user. Suppose the id logged in user is a customer and the record was created by the user who has support role, then it should show 'Support', and if the support logs in then show the id of the person who added(even if its a different support person's id). I can figure out the current user's role. How can I achieve this without defining a separate apis based on role? Is it possible to have same api to get results from db based on query but transform the column based on role.
My initial thought is to create a view helper.
I'll give you an idea for what it could look like. Since you didn't share the name of the model in your question, I'm picking an arbitrary model (Watermelons) that has a created_by relationship to Users. I realize that's a silly choice. I'm an enigma...
app/helpers/watermelons_helper.rb
module WatermelonsHelper
def created_by_based_on_role(watermelon)
if current_user.role == "Support" || watermelon.created_by.role == "Generic User"
watermelon.created_by.name
else
"The Watermelons.com Support Team"
end
end
end
app/controllers/watermelons_controller.rb
class WatermelonsController < Application Controller
def show
#watermelon = Watermelon.find(params[:watermelon_id])
end
end
app/views/watermelons/show.html.erb
...
<p>This watermelon was created by <%= created_by_based_on_role(#watermelon) %></p>
...
The reason why I'd make this a helper method and not a method in the watermelon.rb model is that the method is dependent on the current_user, which the model can't explicitly know each time (assuming you're using Devise or a hand-rolled, Hartl-style current_user helper method as well).
Edit: Per feedback, let's make it a model method...
app/models/watermelons.rb
class Watermelon < ActiveRecord::Base
...
def created_by_based_on_role(viewing_user)
if viewing_user.role == "Support" || self.created_by.role == "Generic User"
self.created_by.name
else
"The Watermelons.com Support Team"
end
end
...
end
Note that I'm implementing this as an instance method, which means you will need to call "watermelon.created_by_based_on_role(current_user)" in the controller or view.

Rails getting access to current user

I'm trying to save in Note which Employee was the last editor of a `Note'
In a View, I'm able to access the current employee like this:
<h4><%= current_user.employee.id%></h4>
But, in a Model, I can't use current_user.employee.id.
So, I'm trying this in the User model:
def self.current
Thread.current[:user]
end
def self.current=(user)
Thread.current[:user] = user
end
And this in the Note model:
before_create :record_update
before_update :record_update
protected
def record_update
self.lasteditor_id = User.current.employee.id unless User.current.employee.id.nil?
end
What I'm getting is the last User in the Users table.
Thanks for the help!
current_user gets the logged in user information from the session. You cannot access session variables from model. If you want to update the Note model with the Last employee who viewed it, do it in your controller(most likely show action of your note or any other action you think would be right)
def show
#note = Note.find(params[:id])
#note.update_atribute(:last_viewed_by, current_user.id)
end
You code might look different from above. But this is the idea

Cross Database Connection with Active Record

I have two websites that each connect to their own unique databases. I need to validate in website 'A' that an email address exists in the website 'B' database. I'm doing the validation as follows:
Called from website 'A's AccountController < ApplicationController class:
config = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
ActiveRecord::Base.establish_connection(config["database B"])
if ActiveRecord::Base.connection.select_values("SELECT "database B".X
FROM 'database B".X WHERE 'database B'.X.email = #member_email")
This call works when I test it in my development and QA environments but fails in my production environment. What appears to happen in production is that the value of the ActiveRecord and also the select get's co-mingled with currently logged-in user's active records, but only in production.
Okay so I've modified my files to the following, based on the feedback. Still not working... Could someone please review the files below and see what step(s) I'm missing? Thanks!
Thanks! I think that is what I did, but I created the 'model', and, being a newbie, I'm not sure if that would normally be generated by Rails...
Still failing, would you mind taking a look at the following and see if you see what I'm doing wrong?
First, this is the 'legacy' database model for the second database that I want to connect to in the existing application (Note that doing the 'Fileload' was the only way I could get this to not error out.):
class MMSDB < ActiveRecord::Base
self.abstract_class = true #important!
config = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
establish_connection(config["deals_qa"])
end
Second, this is the model that calls the 'MMSDB' Model (see above)
class Redirect < MMSDB
def initialize
end
Checking to see if the email address exists in the legacy database, and, if it does, the #increment the redirect count on the # database table 'members'
Do I somehow need to tell the application what table I want to pull from since the table # in the legacy database (members) would be different then in the current application #database (users)
def email_exists?(email)
if find_by_email(email)
user = find_by_email(email)
user.redirect_count += 1
user.save
end
end
end
Then this is the code snippet inside the account controller file.
else
if user == Redirect::User.email_exists?(#email)
#Redirect_Flag = true
else
flash.now[:error] = 'Invalid email or password; please try again.'
end
end
Subclassing ActiveRecord::Base will allow you to make multiple connections to different databases.
module DatabaseB
class Base < ActiveRecord::Base
#abstract_class = true
establish_connection(config["database B"])
end
end
class YourAwesomeModel < DatabaseB::Base
set_table_name "X"
# Use your regular active record magic
end
You will still be able to use your other models with the connection established using ActiveRecord::Base to your primary database.

User model, attr_accessible and admin

I'm building a simple blog-style application. I really only need admin and non-admin users, so it seems like having a simple column in the user model called admin (boolean) will suffice.
I'm using Devise for authorization right now, and I've got the admin column added. I'm trying to set up my default admin user (myself) in seeds.rb, however admin comes out as false unless I add the admin column to attr_accessible. It seems like this would be a security concern, however, and I don't generally want admin users to be able to be created except by another admin. What's the correct, and safe, way to do this?
You want to handle setting the admin boolean internally. Don't expose it to mass-assignment.
Have your user model automatically default the first user (you) to an admin. Use a before_create method for this...
# models/user.rb
before_create :make_first_user_an_admin
def make_first_user_an_admin
self.admin = self.class.count == 0 # sets true if no users exist, false otherwise
end
Then use an instance method to set adminship...
# models/user.rb
def toggle_admin
self.admin = !self.admin
save
end
guard this method in your controller...
# controllers/users_controller.rb
def change_adminship
if current_user.admin
#user.toggle_admin
else
raise "Can't do that."
end
end
You are very correct to leave admin as not attr_accessible, this just disables setting it via mass-assignment. You can still set admin in your seeds by setting it singularly. Example:
user = User.new(:name => 'joe') ...
user.admin = true
user.save

Resources