TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Rails – The Missing Parts

205 点作者 tomblomfield大约 11 年前

27 条评论

dhh大约 11 年前
The proof is always in the pudding. While there are good and reasonable times to introduce &quot;interactors&quot;, this particular example is poor. The tests presented are anemic, and the code is absolutely not any clearer by being extracted and wrapped. I would indeed have kept all this in the controller.<p>The key point for an &quot;interactor&quot; extraction is imo when you have multiple models being created in symphony, like a Signup model. Or if you for some reason need to reuse the behavior.<p>But if all your controllers look like this, with one &quot;interactor&quot; model per action, you&#x27;re doing it wrong.<p>Whatever floats your boat, though. If this is what you prefer, great. But please hold the &quot;beginner&#x27;s version&quot; crap. Plenty of large apps are built with vanilla Rails. Basecamp is one.
评论 #7336166 未加载
评论 #7338421 未加载
评论 #7336094 未加载
评论 #7337339 未加载
评论 #7352497 未加载
评论 #7344676 未加载
ollysb大约 11 年前
Perhaps because it&#x27;s written with examples in java but I often feel like no one in the rails community has ever read Eric Evan&#x27;s Domain Driven Design[1]. It&#x27;s far and away the best material I&#x27;ve ever seen on how to organise large code bases. It covers pretty much every suggestion that I&#x27;ve seen from the rails community. Sometimes the rails community can feel like the fitness industry, everybody just rebranding things that have been done before.<p>[1] <a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215" rel="nofollow">http:&#x2F;&#x2F;www.amazon.com&#x2F;Domain-Driven-Design-Tackling-Complexi...</a>
评论 #7335861 未加载
评论 #7335452 未加载
评论 #7335422 未加载
评论 #7336186 未加载
评论 #7337543 未加载
评论 #7335427 未加载
评论 #7335429 未加载
programminggeek大约 11 年前
I&#x27;ve spent more time thinking about clean architecture and design than most and the conclusion that I&#x27;ve come to is while Ruby gives you all the tools to write clean code and great architecture, it doesn&#x27;t offer the best tools to do that job.<p>Ruby and Rails feel best as a prototyping platform for getting something out the door fast, proving a concept, and not worrying so much about correctness or maintenance.<p>I don&#x27;t think if you are doing a lot of TDD and larger systems that piling on more Ruby and Rails is the right answer. I think once you know what you are working with, a well designed language with a compiler is a huge help and would remove a ton of useless tests and stuff that you end up writing in Ruby by hand.<p>This very likely leads to an API driven system with an API written in a strongly typed, compiled language like C#, Java, Scala, Haskell, or Go and writing your front end in whatever makes the most sense for your team.<p>At that point you get the benefits of a nice rapid development platform like Rails for your front end, and a fast, testable, API written in something else using all the clean code architecture you want.<p>The trick is, you do everything ugly in Rails or PHP or whatever in your initial prototype and you might not even write tests. You just ship working code until your prototype has proven a business case. Then, you move it towards something with lower TCO over time. Make the investment in your code when it makes sense to invest in it and use the best tool for the job at each step.<p>You probably never need to leave the standard Rails MVC stuff on most projects unless they are wildly successful and&#x2F;your long term needs change. Even then, you can probably keep the rails front end stuff and just talk to an API and be very happy.
rjspotter大约 11 年前
I agree completely that the Interactor pattern makes for cleaner Models and Controllers in a Rails codebase. I&#x27;ve used both the Interactor gem and PORO (in a directory outside of &#x2F;app or &#x2F;lib).<p>Having worked with the Interactor gem for a little while once you break things down into small interactors that can be used by the Organizers, I have two main complaints.<p>1) inputs are unclear. With calling new or some custom class method you can use descriptive variable names to say what the object expects to be present to do it&#x27;s job. With the Interactor gem you end up adding in comments describing what keys need be present in the context and what keys will be added to the context so the next programmer can use the interactor you&#x27;ve created without having to go through and grok everything.<p>2) You end up having to (re)create a failure protocol to communicate with the controller and display to the user. We take the AR errors functionality for granted in our controllers&#x2F;views with interactors you have to come up with a similar system.<p>2.5) as a result you end up writing a lot of boilerplate fail! and rollback code<p>2.5.2) and a non-atomic operation like notifying the payment gateway can break the whole model of rolling back and you have to end up raising so your user doesn&#x27;t end up in a invalid state or get charged twice.
评论 #7336532 未加载
casey_lang大约 11 年前
Along the same line but heavier weight than &#x27;Interactor&#x27; is &#x27;ActiveInteraction&#x27;[1].<p>Responds in much the same way active record does, allowing validations, errors, forms built from interaction objects, etc.<p>[1] <a href="http://github.com/orgsync/active_interaction" rel="nofollow">http:&#x2F;&#x2F;github.com&#x2F;orgsync&#x2F;active_interaction</a>
tzaman大约 11 年前
We tried using DHH&#x27;s concerns in place for interactors, but ditched them for PORO&#x2F;service objects because they can be tested outside Rails.
评论 #7336005 未加载
评论 #7335675 未加载
pothibo大约 11 年前
One thing I really enjoy with this post is the conclusion. It doesn&#x27;t try to tell you it&#x27;s the only way, just that it&#x27;s the way they found to fix their problem with the constraints they had, as it should be.<p>Rails is easy to extend, people often forget that. Great post.
edwinvlieg大约 11 年前
We&#x27;ve also come across the limitations of Rails as a one-size-fits-all solution for larger codebases. I don&#x27;t think this is a fault of Rails, but more of the developers using the framework. Software engineering in general has more focus on a wide variety of design patterns and doesn&#x27;t limit itself to one framework. In my opinion, Rails is the best framework to create wonderful web applications. Modeling business logic requires different kind of architectures than the simple MVC-ish structure Rails provides.<p>At MoneyBird we are using the Mutations gem to represent something like the interactors mentioned in this article. One major advantages of Mutations, is that is also does input filtering.<p><a href="https://github.com/cypriss/mutations" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;cypriss&#x2F;mutations</a>
Axsuul大约 11 年前
I&#x27;ve been looking into incorporating this pattern into my larger Rails apps as well. Another benefits of interactions is DRYing up your code for use in APIs. Some of the more popular interactor gems:<p><a href="https://github.com/orgsync/active_interaction" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;orgsync&#x2F;active_interaction</a> <a href="https://github.com/cypriss/mutations" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;cypriss&#x2F;mutations</a>
评论 #7335756 未加载
评论 #7335729 未加载
评论 #7336490 未加载
nwienert大约 11 年前
I&#x27;ve found a happy balance developing with rails by adding two strategies:<p>1) Use presenters for display-only logic to keep controllers concerned with managing requests only.<p>2) Using service object &#x2F; custom classes in &#x2F;lib for actions on models as well as abstracting any common related functionality. Creators, Updaters, Processors, Orchestrators, etc. Keep your models only concerned with data and not data transformation, and your controllers from doing it as well.
评论 #7336138 未加载
评论 #7336017 未加载
wdewind大约 11 年前
This is great, and does not only apply to Rails. In many other frameworks it&#x27;s common to lump business logic in controllers instead of models. Either way you end up with the same thing: eventually you&#x27;ll need to add a 4th (at least) type on to MVC.<p>&gt; Here at Grouper, we’re long-time users of Ruby on Rails – along with other New York startups like RapGenius, Etsy and Kickstarter.<p>Etsy doesn&#x27;t use Rails though, it uses PHP.
评论 #7336539 未加载
kapilkale大约 11 年前
Can anyone recommend a github repo of a Rails app implementing interactors or any of the similar concepts listed in the comments?
评论 #7336050 未加载
sdegutis大约 11 年前
How about just &quot;features&quot;?<p>Maybe there are some &quot;user&quot; features (login, logout, change name) and &quot;cart&quot; features (add&#x2F;remove item in cart).<p>These features would all live horizontally, be able to call each other (design your object graph wisely!) and would never be able to inspect or elaborate on implementation details!<p>These features may or may not talk to some database for its own persistence, but that&#x27;s up to the functions.<p>And the features are pure functions in your language of choice. They have no knowledge of the web, or requests, they&#x27;re perfectly transient. They act on a &quot;state&quot; object that you pass around to them, which in tests is just a blob of memory and in production is a real database or wherever else you store state.<p>It&#x27;s simple, yet so powerful. This is how we do it, and it&#x27;s scaling very nicely.
avitzurel大约 11 年前
As always, the question is should be in Rails or not.<p>I think that the answer is clear, this should not be a part of rails since it&#x27;s not true to all apps.<p>I think that if you want to have something real quick, you don&#x27;t need an interactor&#x2F;service class.<p>When you have a bigger app, you definitely need that, or you will get to a point where you code is split into models&#x2F;observers&#x2F;callbacks&#x2F;lib&#x2F;app&#x2F;concerns and you can&#x27;t find anything.<p>Rails generators are pretty easy to extend, this way, when you generate a new model, you can easily create the service class for it.<p>You can also EASILY create new generators that will generate the service classes for you with your defaults and templates and what not.<p>Not sure Rails is missing that, however, it is definitely a best practice that people with bigger apps should use TODAY.
评论 #7336103 未加载
iagooar大约 11 年前
I recommend this article from the guys from Code Climate, it is really mind-opening: <a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/" rel="nofollow">http:&#x2F;&#x2F;blog.codeclimate.com&#x2F;blog&#x2F;2012&#x2F;10&#x2F;17&#x2F;7-ways-to-decomp...</a><p>The author describes different ways of refactoring fat ActiveRecord models, but most of the ideas can be used outside ActiveRecord, as &quot;best practices&quot;.<p>I have been using some of the patterns described in it and I am really happy with the results. The code becomes more clearly decoupled, is easy to test and results in clean, slim models.
evilgeenius1大约 11 年前
When reading DHH&#x27;s comments it&#x27;s important to remember that the domain model for Basecamp is extremely simple. It&#x27;s a brilliant piece of software that&#x27;s been well thought out, but the underlying domain concepts are extremely basic.<p>I wonder if he&#x27;s ever worked with an app that has a complicated domain.<p>His comments taken from this perspective make a lot of sense. Rails was written for Basecamp.<p>For large apps with real complexity, the rails way falls short.
tuke大约 11 年前
&quot;The nail in the coffin is ActiveRecord callbacks; before_save hooks on one class that modify the state of other objects.&quot;<p>before_save <i>can</i> modify the state of other objects. It doesn&#x27;t have to. One might use it to modify only the state of the current model. You are reaching a bit, blaming the callback, when what you are really concerned with is an awkward and potentially dangerous use of the callback.
GutenYe大约 11 年前
What&#x27;s the different between interactor and wisper? Wisper is better doing the job in your example.<p>interactor: <a href="https://github.com/collectiveidea/interactor" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;collectiveidea&#x2F;interactor</a> wisper: <a href="https://github.com/krisleech/wisper" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;krisleech&#x2F;wisper</a>
seancoleman大约 11 年前
A good litmus test of an experienced Rails developer is how large their &#x2F;lib directories are in relation to project sizes.
评论 #7335960 未加载
评论 #7336143 未加载
评论 #7335951 未加载
reedlaw大约 11 年前
I wrote a blog post along similar lines [1]. The benefits are clear to me: nearly 200 tests run in about a second. For that reason alone I wouldn&#x27;t consider coupling domain logic with ActiveRecord.<p>1. <a href="http://www.smashingboxes.com/domain-logic-in-rails/" rel="nofollow">http:&#x2F;&#x2F;www.smashingboxes.com&#x2F;domain-logic-in-rails&#x2F;</a>
troels大约 11 年前
One thing I can&#x27;t figure out is whether to place my service objects under `&#x2F;app&#x2F;models` or under `&#x2F;lib`. There doesn&#x27;t seem to be a clear consensus on this? I tend more towards the former, because autoload works better during development. Also, I consider them part of my domain model. What do you do?
评论 #7335679 未加载
评论 #7335777 未加载
评论 #7335845 未加载
评论 #7336501 未加载
评论 #7335680 未加载
andrzejkrzywda大约 11 年前
If anyone&#x27;s interested in a more real-life example, then this post presents a Rails controller refactoring from the Redmine project.<p><a href="http://blog.arkency.com/2014/02/rails-refactoring-the-aha-moments/" rel="nofollow">http:&#x2F;&#x2F;blog.arkency.com&#x2F;2014&#x2F;02&#x2F;rails-refactoring-the-aha-mo...</a>
csense大约 11 年前
The first missing part: A language with a sane syntax. For some examples of the multitude of ways in which Ruby syntax is awful, see [1].<p>The second missing part: Ruby is Rails. Trying to learn Ruby <i>at the same time</i> as a modern web framework with all its moving parts? Forget it.<p>The third missing part: Tutorials. Okay, I haven&#x27;t done a rant on this. Google rails tutorial. The first helpful result I get [2], I scroll down. The first meat is &quot;Setting the application home page&quot;. I see this:<p><pre><code> Blog::Application.routes.draw do get &quot;welcome&#x2F;index&quot; </code></pre> Huh? &quot;This is your application&#x27;s routing file which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions.&quot; So it&#x27;s not even Ruby or some recognized Web glue language like HTML or CSS; it&#x27;s some domain-specific language? Okay, I totally don&#x27;t get it, so as suggested, for more details, I should refer to &quot;Rails Routing from the Outside In&quot; [3].<p>This is even more confusing. It says you should do something like this:<p><pre><code> get &#x27;&#x2F;patients&#x2F;:id&#x27;, to: &#x27;patients#show&#x27; </code></pre> Huh? What&#x27;s the deal with the colons and octothorpe? I can guess colon is the signifier for an ID in the URL, but why the pound sign for #show?<p><pre><code> get &#x27;&#x2F;patients&#x2F;:id&#x27;, to: &#x27;patients#show&#x27;, as: &#x27;patient&#x27; </code></pre> And what&#x27;s the deal with the colons?<p>I could go on and on. I&#x27;m sure that with a few hours of pain and frustration, I would be able to figure out exactly all the oddities of Ruby syntax, or the template language, or the DSL whatever, and understand this example well enough to extend it.<p>But that&#x27;s not the point. The point is that, because I have to spend those hours, it means that Ruby&#x2F;Rails is poorly designed. In Django, by contrast, things are almost always simple and obvious.<p>[1] <a href="https://news.ycombinator.com/item?id=5872899" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=5872899</a><p>[2] <a href="http://guides.rubyonrails.org/getting_started.html" rel="nofollow">http:&#x2F;&#x2F;guides.rubyonrails.org&#x2F;getting_started.html</a><p>[3] <a href="http://guides.rubyonrails.org/routing.html" rel="nofollow">http:&#x2F;&#x2F;guides.rubyonrails.org&#x2F;routing.html</a>
评论 #7339877 未加载
dablweb大约 11 年前
I like the interactor gem but don&#x27;t understand why the method activating it is &quot;perform&quot;.<p>Why isn&#x27;t it &quot;call&quot; so it can be swapped out with a lambda, or method reference without hassle?
评论 #7337832 未加载
ksec大约 11 年前
It sounds similar to what Lotus is trying to do.<p><a href="http://lotusrb.org/" rel="nofollow">http:&#x2F;&#x2F;lotusrb.org&#x2F;</a>
评论 #7338508 未加载
clutchski大约 11 年前
I thought Etsy uses PHP. Could be wrong.
评论 #7335770 未加载
ream88大约 11 年前
I would love to take a glimpse on the Basecamp code, dhh ;)