New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Earlier Draft: Concerns #3
base: refactoring
Are you sure you want to change the base?
Conversation
Under "Disadvantages", points 2 and 3 are actually alternatives -- not really disadvantages. You might want to mention that another disadvantage is, it could be argued, that Concerns hide the complexity of the Object. Also, it is often times harder to find how a certain object has access to a method, and where that method is defined. "PORO" stands for "Plain Old Ruby Object", and comes from the Java acronym of "POJO" (perhaps another language coined it earlier). Saying Service Object is also known as PORO is not really correct. PORO is just any plain ruby object, that doesn't depend on any libraries in itself. |
Another thing worth mentioning is trickiness involved when testing Concerns that are included into several models. Do you test each model for those included methods? Do you create a dummy model/class and test the concern once? Do you use RSpec's shared examples? Worth to think about Concern method that rely on some state of the model. Say you have a method like this in your Concern: def by_email
where(email: @email).first
end That Concern now depends on the fact that the including model must have a |
I dislike concerns hugely. Now that I have that off my chest... @gylaz I used to do shared spec on these kinds of things, but that was when I was 'speccing' instead of 'testing' as I do now. When I need to test any mix-in, I create a test class, mix in the module, then test the behavior. `At least this was how I used to do it. These days I just extend self on modules and test them directly. module SomeShitHere
extend self
def a_function
#noop
end
end
it "blah blah" do
SomeShitHere.method.must_equal nil
end |
@dreamr Thanks for the response.
Thanks. |
@justin808 I write small focused, isolated classes. I also stay away from loading dependencies I don't need. Concerns are inviting big-balls-of-shit, which I don't like. They keep you firmly in Rails-land, and they serve no purpose except to create highly coupled junk-drawers. A much better idea would be to extract business log out into PRO (pure ruby objects). These can be modules, classes, whatever. But they should have well-defined boundaries. Rails in general encourages highly coupled messes, which is why they always turn into a rescue at some point if they live long enough. Off with the rant and onto one of my favorite topics, extend self. Extend self is essentially a module-wide module_function call. It indeed turns all the 'instance' (which modules don't actually have) level stuff into class level stuff. As I write as much stateless, immutable objects and functions as possible in my code, I end up using extend self a lot. I also create a lot more modules than classes and methods commonly delegate to a stand-alone module, ie: module CarDiagnosticRecipeRunner
def run(recipe)
...
end
alias_method :call, :run
end
class Car
def run_diagnostic(recipe)
CarDiagnosticRecipeRunner.(recipe, self)
end
end Whereas I think you tend to use modules like so: module CarDiagnostics
def run_diagnostic(recipe)
...
end
end
class Car
include CarDiagnostics
end |
Rails Concerns
large model file into logical chunks with associated tests.
Why Concerns and Not Plain Ruby
etc.
pitfalls and why not the consistency of Concerns?
Where to put concerns
app/models/concerns
.such as
app/models/user/
.Steps
included
block.include
statement in original model class:Another Concern Example
Concerns: Didn't Show You But Useful!
Concerns Summary
Applicable Situation
Solution
The giant model can safely and easily be broken down into logical chunks (concerns), each with a
correspondingly smaller spec file per concern.
Advantages
because using concerns involves simply moving the methods and tests into
separate files. And code accessing those methods does not need to change.
the right source and test file.
Disadvantages
organized. In other words, there's no real changes to the API of the model.
multiple models, a Service Object, aka PORO, better groups the logic.
choice.
Concerns References