Having transitioned from Django to Rails nearly a year ago, this post reminded me of django forms[1]. When I used django, I didn't think much about them, but moving to Rails, I felt something was missing. Why do validations live only/primarily on the model? Doesn't it make more sense to do validation higher-up the chain to filter mistakes and potentially harmful input?<p>Also a good point about the `attr_accessible` concept. It always felt like a bit of a crippled way to perform authorization. That said, I'm not sure this comment is completely valid:<p><i>> attr_accessible suffers from context blindness: you’re frequently going to have an end user UI and an admin UI. You want admins to have access to more fields.</i><p>Whilst it's not the most elegant, you can (and should) define `attr_accessible :x, :y, :z, :as => :admin`<p>but you have to remember to use something like `MyObj.create({x: 'a', z: 'b'}, :as => :admin)`<p>[1] <a href="https://docs.djangoproject.com/en/1.5/topics/forms/" rel="nofollow">https://docs.djangoproject.com/en/1.5/topics/forms/</a>
I really like this approach. I use something similar for my work, however this has a much nicer API.<p>Often these patterns are treated and discussed as an either/or decision, which I don't agree with. There are many places in an app where the default and simple Rails way is the right choice. However as apps get more complex, there is also a need for approaches like the one presented here.<p>My rule for choosing the right approach is this:<p>If it's just a simple CRUD controller where it receives input from a simple form and writes attributes to a single model, with no AR callbacks involved, then omakase is perfectly acceptable. In that case I don't want to have to jump through all kinds of hoops and overcome unnecessary friction added by enterprisey patterns.<p>However, as soon as I have to use AR callbacks, add more lines to my controller action, or touch more than one model, that's a clear indication that a service object makes sense.<p>Mutations looks like a great solution for the latter case. It brings in some DCI goodness as well. The key is that some operations require complex context (object graphs, permissions, dependent operations), and that context should be treated as a first class citizen.
I'm a big fan of this pattern. We use a smaller contextual form process that includes ActiveModel::Validations and provides some simple defining methods, and does a very similar thing. Since most services / mutations are generally bound to a form, it's just called BaseForm, and its children are LoginForm, TweetForm etc.
I'm glad to see rails devs are finally coming to their senses and exploring other patterns for building applications. SOA, command objects, etc. have been a pretty common pattern in "enterprise-y" frameworks for awhile. This is making rails look more like grails, which I think is a good thing.
Is there a reason why it was not created with multiple commands / methods in mind? :<p><pre><code> class UserService
service :signup do |config|
config.required do end
config.optional do end
config.execute
# signup stuff here
end
end
service :delete_account do |config|
config.required do end
config.optional do end
config.execute
# signup stuff here
end
end
end
</code></pre>
This would also make it possible to do service description and even expose a json or xml api using just this.<p>But I guess the controllers are created for this. DHH says controllers are responsible for mailing and stuff, which is more correct than in the models with callbacks.
This seems like a great idea! I have a few thoughts that comes to mind, perhaps others can chip in:<p>- How can this be used in tandem with strong_parameters; should ensuring the structure of params be a responsibility of the controller or the mutation (I'm leaning towards the former)? [1]<p>- How can validation duplication between models and mutations be avoided? In the example 'string :email, matches: EMAIL_REGEX' was used, but presumably one will still validate the email in the model. I'm guessing there are solutions to this, perhaps the existing model validation can somehow be used?<p>[1]: <a href="https://github.com/rails/strong_parameters" rel="nofollow">https://github.com/rails/strong_parameters</a>
I almost fell off my chair laughing when I saw "Rails" and "Security" and "Maintainability" in the same sentence.<p>A quick search here itself on HN will show you how immature and security-hole ridden Rails is. Built for, and by, HIPSTERS!