6 ms·
Put Callback Logic Into Callback Objects [Rails]
- JonWood 15y agoThis strikes me as being similar to extracting bits of a model out into modules that then get included back into that model. It looks like you're reducing the complexity of the model, but in fact you're just hiding it elsewhere, without making it any easier to stub things out.
- nagnatron 15y agoYou're right that it's similar to extracting it to a module since (in this example) HashGenerator.new is evaluated with the class and in my Request spec I can't exactly stub HashGenerator.new to return a double. How would you do it?
- camwest 15y agoCreate a RequestFactory which is responsible for creating valid requests, put the hash generator in there. Then use the factory in the controller instead of directly creating the model. That way you don't have the indirection of an ActiveRecord callback and you have your process of creating a request and assigning it a unique hash in a straightforward single process.
- JonWood 15y agoI'm starting to use service objects, which are responsible for coordinating things when multiple models are required to perform an operation, or complex business logic is involved. James Golick has a great blog post on that approach at http://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome-the-way-i-write-rails-apps.html http://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome...
- dbkbali 15y agoYes I am wondering whether it is that much different than including a concern module, at the end of the day you still have to test the code. Interesting approach though.
- soveran 15y agoYou may run into race conditions when two processes end up saving an object with the same hash_id. The check and the object creation should both happen inside a transaction.
- nagnatron 15y agoGood point. Thanks.
- bhousel 15y agoI'm kind of curious why you use SecureRandom.hex and then check for uniqueness, rather than just using SecureRandom.uuid? Edit: Nevermind, I realize now that SecureRandom's uuid isn't really a uuid, in that sense. It's just random.
- gcao 15y agoShameless plug here. If you use the Aspector gem I created, you could move validation logic into an aspect and test it. And apply aspect is very easy. Here is what the code will look like. class Request < ActiveRecord::Base end class RequestValidation < Aspector::Base target do def has_unique_hash_id? exists?(:hash_id => hash_id) end end before :create do hash_id = SecureRandom.hex(12) until has_unique_hash_id? end end RequestValidation.apply(Request)