I'm using Authlogic. I've got an Entry model and there is a validation method that I want to skip if the request was made by a logged in user (anonymous users are also allowed to create entries). I assume that UserSession.find would not be usable from inside the Entry model like it is from a controller. What is the best way to handle this situation? Do I need to write a custom save method of some sort and call it programmatically from the EntriesController? Or is there a way to check for login state from inside a model? I'm guessing that I wouldn't want to do that anyway, since the model should be in charge of object state and not application state.
Create a virtual attribute on Entry called logged_in.
attr_accessor :logged_in
In the controller, set entry.logged_in to true if the user is logged in, false if not. Then you can use that attribute in the validation method.
validate_on_create :my_check
def my_check
unless self.logged_in?
# add errors
end
end
You can use
valide_on_create :my_check, :unless => logged_in?
Related
I've got a model #record_request that takes in a unique identifier and saves it to the database - the model can be later used to fire a bunch of API requests off to an external database to do it's work.
Thing is, I don't want the user to be able to save the value in the Rails app, if it can't be queried in the remote database.
I've tried creating validations and creating Rspec tests, but all of them require my #current_user variable with all the api_token and referesh_token and other OmniAuth goodies needed to make an autenticated API call...
So I'm kind of stumped. Where is the best practice place to put a validation rule of this kind.
I'm thinking I'll have to put something in my controller on :create that makes the call there and raises errors/flashes that way... but then it seems like I've got a load of code on my controller, and I've fallen for a fat controller anti-pattern, no?
What is the best practice?
Here is an example from a project I'm working on, this code is written in the model
after_validation :should_validate_match?, on: [:create, :update]
def should_validate_match?
if self[:type] == 'Match'
self.answers.each{|ans| self.errors.add(:answer, "match cannot be null") if ans.match.blank?}
end
self.errors.empty?
end
You could test the authentication in custom method triggered by a before_save callback in your model.
Something like:
before_save :do_this
def do_this
if name_of_attribute.blank?
return
else
# api call to test authentication
end
end
If a record request has a reference to user you shouldn't need access to the current_user helper.
A model method starts with the following logic:
def calculate_vat
if self.country.blank?
flash[:danger] = "Please select country first"
redirect_to edit_organization_path(self) and return
end
if ["BE", "CZ", "ES", "LV", "LT"].include? self.country
return 0.21
elsif etc. for other countries.
end
end
Is this not possible within a model method? In the controller, the model method gets called upon using #organization.model_method. It produces the following error in development: undefined local variable or method 'flash' for #<Organization:0x00000007298a68>.
Update: I understand now that it's impossible to use flash and redirect in model method. But how to solve this? Only a specific group of users will ever deal with this model method; so I don't want to make country required for all users. A custom requirement seems impossible because there are no model variables upon which to base such a validation, it's a matter whether a user will ever get to certain checkout pages.
Would the best solution perhaps be to define a private controller method that is called upon from inside the controller just before calculate_vat is called upon?
This is senseless.
Fire the desired flash message in the controller's action after the method is being called and that's it.
Actually, everything you do in the model_method is a pure validation, so just define it properly:
validates :country, presence: true
In my rails application I have a model named "User". User has an column email and a column billing_email. When user creates account he enters the value for user.email. The column billing_email stays empty.
Inside the application I want to use "user.email" if "user.billing_email" is still empty. So unless user has enters value for his "user.billing_email", "user.email" is used.
Can someone point me in the right direction with this? And is the best place to put such code? Inside a helper or inside the user_model itself?
Override the getter in your model:
def billing_email
super.blank? ? email : super
end
But you'd rather use another method name, or keep the same name but in a decorator for instance.
I suggest you to create a new method that checks the presence of the billing_email and returns it if present, otherwise it defaults to email.
class User
def valid_email
billing_email.presence || email
end
end
you can override the billing_email
class User
def billing_email
read_attribute(:billing_email).presence || email
end
end
but I normally avoid this because it can lead to some side effects when the model gets saved or displayed.
In fact, in some cases your code may end-up storing the value of email if billing_email is blank, duplicating all the values.
It's better to go with a custom method.
I am trying to add current user information to record using ActiveRecord callback, but I don't see way how to do that.
I tried Thread.current[:user], but in results I see that thread value is accessed from another user sessions.
I am using Passanger in production, but in the same time I am using acts_as_audited who get user value correctly.
Whats the best/safest way how to do that?
The current user is not accessible from within an ActiveRecord model. This is due to the separation of concerns in Rails--the current user and the session are concepts that pertain to the realm of the controller.
You need to get the relevant data and pass it into the model in order for your callback to work. One way to do this is with an accessor method:
# model
attr_accessor :current_user
def my_callback
# do something with current_user
self.some_attribute = current_user
end
# controller
#model = MyModel.find(params[:id])
#model.current_user = current_user # assuming you have a controller method that does this
#model.save!
You should rename the current_user accessor to be meaningful: eg. if you are tracking the author of a blog post, call it author or responsible_user or some such, since current_user means nothing once the model is saved.
So, here's my problem. I currently am building a simple authentication system for a rails site. I have 3 classes for this: Person, Session, and Role. In my Person model I have defined method_missing to dynamically capture roles according to this guide.
In my application_controller I have some logic to deal with logins and log-outs, the result of which gives me the currently logged in user via:
#user = #application_session.person
Where #application_session is the current session
Now in one of my controllers, I don't want anyone to be able to do anything unless they are an admin, so I included:
before_filter #user.is_an_admin?
This raises a NoMethodError, even though I have method_missing defined in my model. I tried defining is_an_admin?, having it always return true as a test, and that works.
According to this question, I think the problem might have something to do with proxy associations. When I run:
puts #user.proxy_owner
I get a session object, since each user (Person) can have many sessions, and I got my user (Person) from the current session.
I am very confused why #user.is_an_admin? is not calling the method_missing method in my Person controller. Please let me know if you need more information or code snippets.
I am using Rails 3 on Ruby 1.9
I'd consider a method_missing an overkill for such task.
Now, if you have Session class, which belongs_to User, then you can have this:
class Session
belongs_to :user, :extend => PermissionMixin
end
class User
include PermissionMixin
end
module PermissionMixin
def admin?
if cond
true
else
false
end
end
end
P.S. Check cancan, perhaps it'll suit your needs better.
I use a similar permissions check in my system to check the User > Role > Permissions association:
User.current_user.can_sysadmin?
In my controllers I have to instead use:
User.current_user.send('can_sysadmin?')
This may work for you as well.
I have solved this by moving the method_missing method to my application_controller.rb. I change the logic of the method a little to check for a user, and if found, dynamically check the role. If things were not kosher, I had the method redirect to root_url or return true if the user matched the requested roles.
Finally, in my reports controller, I used before_filter :is_an_admin? and got my desired results. However, I am still unclear as to why method_missing had to be defined in my application controller as opposed to directly in the Person (aka #user) model?