I want to block destroy and delete in the User model only and I want to block the callback. In few words I want to block any possibility to delete a user record. I tried by overriding destroy and delete methods but they are not called and the user is alway deleted.
class User < ActiveRecord::Base
def destroy
end
def delete
end
end
I do not want to use any gem related to this, so do not cite any gem. I am not sure if overriding those methods is a good idea, probably I should just create a 'deactivate' method and leave the default delete and destroy method there, just in case I will need them in the Rails console
Refer to Rails API Methods.
It's not necessarily a bad thing to override these methods provided you know what you're doing and the consequences. Sometimes it's the cleanest way to solve a problem.
My recommendation is looking at the following Rails API method documentation entries and ensuring you're not missing any important actions here.
#destroy
#destroy!
#delete
By creating those methods in your model, it will override anything in the inherited Rails API so it should work just fine.
I'm not sure that I understand your question fully.
One way to do this is to make the destroy and delete methods private.
You say that the methods never get called, but that the objects are being deleted anyway. How does this happen? Are you deleting them from a collection? You may need to override a class method of User rather than those two instance methods.
Related
I am new to mocking and stubbing, but I think I have a circumstance where their use would be ideal.
In my application, when a user saves a Product, an after_save callback fires that creates Publication instances which cause the product data to be sent to certain 3rd parties via API.
I have a request spec for Product that tests my CRUD operations.
If I stub either the API methods or mock the Publication model, will those mocks/stubs be used in my spec even though they are actually called in the Product after_save callback? I'm confused about this point.
Update
I figured I would just do it like this:
Publication.any_instance.stub(:publist).and_return(true)
And do that at the beginning of my test. That way whatever instance is created would be handled. Is that how it works?
Yes that stub will do what it says and the publist method on any instance of the publication class will always return true.
Instead of putting it "at the top" though do something like.
context 'when there is a publist' do
Publication.any_instance.stub(:publist).and_return(true)
it 'should ...' do
...
end
end
then if required you can do tests without the stub, or tests where publist returns false in other context blocks and be nice and clear in the spec.
I have a Log model which registers some actions done to a Foo model. That means, every time I create or update a Foo instance, I have to create a new Log instance for its table to register the corresponding action. Where does this creation belongs to? To Foo's model or to Foo's controller?
I was thinking, in the model I can use the before_save method and that would keep my controller skinny, but I'm not sure if it's right to put that logic there. Thanks
Logs can be used anywhere, it depends on your need to put them into right place.
For this case, your logging seems related to model changes but has little to do with HTTP requests, I think the better option would be model related place.
Option 1: after_save and after_update callback, not before_save. (You only want to log it after change already made effect)
Option 2: Model Observer.
I myself prefer Observer in this case because Log is not something inside this model so better not to use model callback. Also Observers allow you to add more things later easier. The downside is Observers are easy to be forgot, not a big deal if you can overcome it.
I'm building an audit trail that needs to know which user is currently making the request. My audit trail is built using ActiveSupport::Notifications to receive an even that needs to be audited.
What I would like to do is use an ActiveSupport::Concern to encapsulate the logic for my audit needs, so that I can easily add auditing to any model in my system.
In general this is easy to do. I even blogged about it a while back. However, I'm having a hard time figuring out how to get the current user that making the request to the web server, so that I can log who is making what changes in my audit trail.
I know there are a ton of questions about "how do I get current_user in my model" but I'm not asking about doing it in a model, so I'm hoping there is a better set of answers. Since my audit code is infrastructure related, I am hoping that there is some way I can tap into the current request that is being processed, or something else that would definitively tell me who is currently logged in / making the request.
I've read a lot of "answers" that say to use thread storage and put the current_user in there. I don't like this answer for many of the reasons that others don't - there is no guarantee that thread storage is safe. it could bleed across multiple requests if the server uses the same thread to process multiple requests, etc.
so... given that I am not trying to access current_user from my model, but rather from either an ActiveSupport::Concern or ActiveSupport::Notifications event subscription, are there any good options for me to know who the current user is?
Update
I'm using devise for authentication, which uses Warden on the back end. devise retrieves the current_user by calling request.env['warden'].authenticate(:scope => :user) (assuming i use a "User" model for authentication).
Is there a way for me to access the current request object from within my concern or notification subscription? Back in my .NET days, I would have been able to call HttpContext.Current.Request and all would be good. What's the equivalent in Rails?
Rails' ActionController::Instrumentation has explicit support for this, using append_info_to_payload.
Add a method to your ApplicationController:
def append_info_to_payload(payload)
super
payload[:current_user_id] = current_user.try(&:id)
end
now, when your observer is called back, the information will be in the event.payload:
ActiveSupport::Notifications.subscribe /process_action.action_controller/ do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
current_user_id = event.payload[:current_user_id]
# do something interesting with current_user_id here
end
You already have the answer, what you're doing is the same as when people are accessing the request in models. The current_user is just a method defined on your ApplicationController. When you're not in a controller or other class that inherits from it, you can't access that method.
HttpContext.Current.Request << I would bet a lot that this uses thread storage. Any other solution we find will also be thread storage at some level or another.
Either pull out what you need from the request in the controller and pass it down as parameters, or use thread storage -- but this is inherently dangerous anyway. What if you start using delayed job to do the notifications or something?
In one of my programs I use a model called User and then use user = User.create(attr) where attr are the necessary attributes for this action. Then to destroy this I use user.destroy. However, I see that in the API Doc the destroy instance method for ActiveRecord::Base is deprecated -- is there a new/better way to go about destroying a model object?
It hasn't been deprecated, it's just been moved. The destroy method is now a member of ActiveRecord::Persistence instead of ActiveRecord::Base. However, you still call it the exact same way:
user.destroy
I am doing a check on a user model to determine whether s/he has one or more task_list, if she has more than one task_list only then she is allowed to delete it, otherwise an exception is thrown. I basically have an method called delete_list in the user model to allow for short hand deletions such as user1.delete_list(list1)
I am debating whether to put the check in CanCan where it would be apply as a before filter on the controller or whether to have it in the user model as well . What is the recommended practice?
I think a good DRY approach to this would be to create a method in your model that tests whether a delete is allowed. Then use that method from your controller or from ability.rb. IMHO I think having complicated permission/business logic decoupled from CanCan is better when there is a chance you might change to a different permission system in the future.
In your model:
def can_destroy_list(list)
... Do check here ....
end
In ability.rb
can :destroy, List do |list|
user.can_destroy_list(list)
end
Your controller and views can then also use can_destroy_list directly on the model instance if nessary or use: if can? :destroy, #list