0

I am using after_find in my model, but wanted to disable in in some cases. And i am using .where still after_find is running but in document its said that it works only for following methods. Why is it so?

all
first
find
find_by
find_by_*
find_by_*!
find_by_sql
last

my api(grape framework) is

delete '/delete_user' do
  user_id = params[:user_id] #authenticate_current_user!
  @user_profile = ::UserProfile.where(user_id: user_id).
  @user_profile.destroy_all
end
shahana hamza
  • 107
  • 1
  • 1
  • 10
  • Which document did you get that information from? The [rails documentation](http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html) says: *"an `after_find` and `after_initialize` callback is triggered for each object that is found and instantiated by a finder"*. And the `find_by_*` methods were deprecated/moved out of core rails since v4, and removed completely in rails 5. – Tom Lord Nov 16 '17 at 10:35
  • Can you please show your code? What do you mean by "disable in some cases"? There is likely a cleaner solution to your problem that does not involve `after_find` at all. – Tom Lord Nov 16 '17 at 10:37
  • Saw in http://guides.rubyonrails.org/active_record_callbacks.html . Has added the code also. – shahana hamza Nov 16 '17 at 10:49
  • Can you describe in natural language when do you want NOT to fire this callback? – AntonTkachov Nov 16 '17 at 10:50
  • Saw "The after_find callback will be called whenever Active Record loads A RECORD from the database. after_find is called before after_initialize if both are defined." this also in documentation. I doubt if its applicable to where clause as it written A RECORD in it. – shahana hamza Nov 16 '17 at 10:51
  • I wanted to disable when this api in this question is called. – shahana hamza Nov 16 '17 at 10:52
  • @shahanahamza Can you please show **all** relevant code, and properly describe what you are trying to achieve? I'm very reluctant to provide a (potentially poor/misleading) answer to a question that hasn't been properly explained. What have you currently written in `after_find`? Why have you done that? Why do you want to bypass that here? There are all sorts of solutions that may be a better fit for your problem, but I can't really suggest something without knowing what the problem **is**. – Tom Lord Nov 16 '17 at 13:30

1 Answers1

1

The after_find callback is not being invoked by your where call; it is being invoked by your destroy_all call. destroy_all will instantiate each UserProfile object (and its associated objects) and call its destroy method, one-by-one.

If you want to delete all the UserProfile objects immediately, without instantiating them (and skipping all callbacks), then you can call:

UserProfile.where(user_id: user_id).delete_all

More information on the differences between destroy_all and delete_all can be found in other answers on StackOverflow, but the differences that you care about are:

  1. it will not instantiate the record
  2. it will not delete associated objects
  3. it will not invoke any callbacks

I would recommend that you not use after_find the way you are using it. There are lots of ways to skip callbacks but almost nobody uses after_find. (compared to after_create, for example)

The options for skipping after_find callbacks are limited. There are no built-in Rails methods for doing so. (except as described above) If you absolutely have to keep the callback, then your best bet is to add a conditional to the callback definition:

after_find :foo, if: -> { <some logic> }

If you use a conditional like that then you have to start thinking about how that variable is read and set in a multithreaded environment, and how do you handle concurrent requests without creating a race condition, and it sends you down an ugly path that is better handled by not using after_find in the way you've described.

anothermh
  • 9,815
  • 3
  • 33
  • 52
  • No. when i tried in my console, using **where** clause, after_find is getting invoked. For ex: User.where(id: 2) invokes after_find method. – shahana hamza Dec 10 '17 at 06:43
  • @shahanahamza That is only because you are running it in the console. If you run `UserProfile.where` in the console then `irb` will instantiate each record so it can conveniently display them for you. When `irb` instantiates the record the `after_find` callback is triggered. This *only* happens because the console is instantiating the records to show them. – anothermh Dec 14 '17 at 03:57