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

科技回声

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

GitHubTwitter

首页

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

资源链接

HackerNews API原版 HackerNewsNext.js

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

On logic in a Rails app, revisited 6 years later

58 点作者 alisnic将近 6 年前

13 条评论

archey1将近 6 年前
Been doing Rails development for 6+ years. The most maintainable codebases I&#x27;ve worked on had some kind of service layer between the controller and the model. We used the &quot;interactor&quot; gem to create individual units of business logic that we could reuse and piece together into larger &quot;flows&quot;. Business logic stayed in the interactors, persistence logic in the models. This lead to skinny controllers, skinny models and many, many many reusable skinny services. One fortunate side effect is that all these pieces became extremely easy to test in isolation, as well as integration tested.<p><a href="https:&#x2F;&#x2F;github.com&#x2F;collectiveidea&#x2F;interactor" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;collectiveidea&#x2F;interactor</a>
评论 #19953136 未加载
评论 #19950761 未加载
kudokatz将近 6 年前
A lot of discussion I heard around writing idiomatic Rails led to really fat models. Given the number of database trips back and forth with ActiveRecord, it didn&#x27;t end well.<p>Eventually as the system grew it was much better to have bulk-interfaces of data-only for reads that completely bypassed ActiveRecord. Logic in controllers was also <i></i>eventually<i></i> factored out and re-used elsewhere.<p>My experience is that a lot of advice for Rails centers around small-to-medium size applications, and of course practices that are efficient and practical for apps of that size might not work exceptionally well in other scenarios.
评论 #19949965 未加载
x0x0将近 6 年前
What jumped out at me was this:<p>&gt; <i>To give you some context, it was a time when I was starting to grow as a Rails&#x2F;Ruby developer. I was reading a lot of blog posts on the topics and (as any young developer with a lot of self esteem) I started to have very strong feelings as to how Rails code should be written.</i><p>Lots of programming advice is like this -- people definitely make sure not to let being a beginner, or close to, stop them from lecturing people with a decade plus of experience building applications how to do things...
Railsify将近 6 年前
We use this library to isolate business logic: <a href="https:&#x2F;&#x2F;github.com&#x2F;cypriss&#x2F;mutations" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;cypriss&#x2F;mutations</a>
esaym将近 6 年前
Related: The &quot;AnemicDomainModel&quot; <a href="https:&#x2F;&#x2F;www.martinfowler.com&#x2F;bliki&#x2F;AnemicDomainModel.html" rel="nofollow">https:&#x2F;&#x2F;www.martinfowler.com&#x2F;bliki&#x2F;AnemicDomainModel.html</a><p>In other words, there should be another layer in-between your DAO (data access object, ORM, etc) and controller. The &quot;Model&quot; in MVC was never meant to represent a single row of a database in object form. A Model should have a DAO but a Model should not be a DAO.
评论 #19950137 未加载
nurettin将近 6 年前
spring boot enforces the idea of having a service layer between controller and model to act as a glue between the two, so the controller can focus on controlly things like authentication and handling request s&#x2F;responses (http,ws,rmq,whatever) and the service can handle creating objects, reading&#x2F;saving entities and making calculations.<p>It just makes things easier to digest because you know what resides where. If I returned to rails, I would be using this approach more.
rogem002将近 6 年前
I&#x27;m currently building a Rails app with a event driven development (EDD) approach. This post makes me tingle.<p>After building apps with easily way to much logic in controllers, EDD feels like a much cleaner approach for long term scale. But finding the right EDD approach that feels like &quot;the rails way&quot; has sparked a lot of debate within our team, especially around the &quot;does this actually help&quot; argument.<p>I&#x27;m petty curious about others experiences :)
burlesona将近 6 年前
I&#x27;ve found that a pretty simple technique along the lines of what&#x27;s shared in the article makes complex Rails apps much more maintainable. Most of this applies to any MVC style app&#x2F;framework.<p>I follow these rules of thumb:<p>1. Controllers should only handle converting HTTP to ruby calls. That includes logic that is specific to the request flow, like parsing params or authenticating cookies, but nothing else.<p>2. Models should only handle read&#x2F;write on their own table. You can use associations, but no referencing another class name inside of a model. No after_* callbacks (and try not to use callbacks at all).<p>3. What Rails calls &quot;views&quot; should be though of as simple html templates with loops and simple if&#x2F;else, but no complex logic.<p>4. Don&#x27;t use Rails Helper Methods. Just don&#x27;t.<p>All by itself this works for toy apps, but now you&#x27;ve got holes where complex presentational and procedural logic has no place to go. So you plug those gaps with two kinds of domain objects: view objects (for complex reads) and action objects (for complex writes).<p>View Objects (more often called Presenters in Rails land to avoid the conflict with the templates, which rails calls &quot;views&quot;):<p>These are used to wrap up any kind of complex, multi-model view. So for example, when you have something like an &quot;account settings&quot; page, you probably need to fetch the user and some associated models, maybe billing info, etc. You can make a simple object that takes in URL params in its constructor, efficiently queries whatever is needed to present this page, then freezes. Now you can put whatever data and logic is needed for the template here, and it&#x27;s very easy to unit test the queries and the individual bits of logic to ensure they&#x27;re correct.<p>Action Objects (sometimes called Mutations, Commands, Interactions, Services, or Procedures):<p>These are used to wrap up any kind of mutative procedure. They should take in a set of inputs, and when called, perform some kind of action (for example, running through all the steps of user registration). These should be written functionally, and should be idempotent whenever possible. Again, wrapping the code up this way makes it very easy to unit test, and to stub in external dependencies when relevant.<p>These patterns make it really easy to follow what&#x27;s going on in your app - easy to add new behavior and easy to walk through complex business processes step by step since everything happens in one control flow. And of course you can compose these objects together for the most complex flows. The simple and stable interfaces help keep your program easy to reason about and allow you to work on individual parts in isolation with confidence.<p>I&#x27;ve used those patterns over the last ten years or so with great success, and more recently have been helping my team at Atlassian gradually convert what was a somewhat messy older Rails app. Happy to answer questions if anyone has any :)<p>— Edit —<p>Just to add, there’s one more big benefit, which is that if you code this way it becomes trivial to replicate any of the behavior in your app from the Rails console. Of course this is the same reason it’s easy to test when you build this way, and writing tests is more important than poking around in the console. But when I’ve worked with people who aren’t as in love with testing as I am, I’ve found that they get more excited when I show them how this puts all your apps behavior into an interface that’s very easy to drive from the console. :)
评论 #19950645 未加载
评论 #19953170 未加载
评论 #19950850 未加载
andrew_wc_brown将近 6 年前
I&#x27;ve been using Rails since version 0.8.6 and have apps as old as 8 years I&#x27;m still maintaining. I&#x27;ve had teams as large as 20 on a single rails codebase.<p>You do not need anything other than the MVC pattern.<p>I would love to see the claimants of these needed abstractions post their code so I could refactor and show you how you&#x27;re wrong.<p>If you make good use of your base controllers you can reduce controller code to next to nothing.<p>If you avoid Rails abstractions such as scopes use callbacks sparingly and focus on writing raw SQL instead of using Arel&#x27;s query builder your models are easy to manage.
评论 #19953250 未加载
miki123211将近 6 年前
The original post sounds very much like what Robert Martin is proposing.
revskill将近 6 年前
Sharing business logic between models&#x2F;controllers&#x2F;views often leads to a mess.<p>There&#x27;s a reason to just write business logic code at only ONE place, the controller.<p>You&#x27;ll thank yourselves years later when you revisited your code. Just one place to look for.
评论 #19950745 未加载
评论 #19950484 未加载
ravenstine将近 6 年前
I think it all depends on <i>where</i> the logic is placed. Controllers shouldn&#x27;t have much business logic in them, but moving logic out of a controller or a model isn&#x27;t necessarily better if it&#x27;s done in an obfuscationary way.<p>The problem is that the patterns provided by Rails and suggested by the Rails community <i>encourage</i> &quot;needless indirection&quot; more than they do actually managing logic in a sane way. Concerns, though they definitely useful for some things, end up becoming dumping grounds for loosely-coupled application logic. I know that the same could be said for just creating modules without ActiveSupport::Concern, but the existence of ActiveSupport::Concern seems to have suggested to a lot of Rails developers that the de facto answer to fat controllers and models is to just dump excess logic into these &quot;concern&quot; modules.<p>ActiveRecord in itself is another fundamentally flawed concept in Rails because it treats <i>data</i> and the <i>interface</i> to that data as one in the same. Models become dumping grounds for a ton of seemingly data-oriented behavior that probably better exist as <i>helpers</i>. I like the idea of ActiveRecord, and I seriously loved it when I first learned Rails, but every Rails project I&#x27;ve encountered contains these needlessly fat models with lots of overridden&#x2F;custom attributes(that could have been helpers), callback after callback, etc.<p>An alternative example exists in Ember Data, where the data and interface are split between concepts: The &quot;model&quot;, the &quot;adapter&quot;, and the &quot;serializer&quot;. This keeps the logic around data very well organized and interoperable(i.e. switching adapters). Models in Ember can still have custom attribute getters, but I still say that it&#x27;s best to try to avoid those if possible and instead look to creating helper functions first.<p>I guess the point of what I&#x27;m saying is that Rails developers think too much in terms of object-orientation, which leads them down the path of thinking about relationships in a way that encourages bloat. In other words, the mindset becomes that where if some behavior has to do with the concept of a Post, for instance, then that behavior should <i>belong</i> in the Post class(without taking much account into whether that code only involves the <i>view</i> or data persistence). Logically, it makes sense from an OO point of view, but then you&#x27;re going to end up with a pile of code in one place that you will inevitably extract into a &quot;concern&quot; which you&#x27;ll have to &quot;include&quot; in other models that share said behavior.<p>Often times, just creating a set of functions&#x2F;methods is simpler and more understandable. They don&#x27;t have to be a part of a specific model or a class, but just be available when needed. In Rails, most of the time that&#x27;s the view, sometimes the controller, so helpers in Rails are perfect for that. Helpers are contained in modules, but with the way they are integrated into the application, you don&#x27;t have to think much about that.<p>Business logic that is more complex or falls outside the scope of helpers should go into Ruby code that doesn&#x27;t depend on Rails, but can just be imported and used within a Rails app. This not only creates a separation between business logic and the logic of rendering HTTP responses, but refraining from making all your code Rails-centric means that the business logic should be easier to test in isolation and faster without all the overhead of Rails.
jsjkkkkkkkkk将近 6 年前
Rails is opinionated and forces a literal sense of MVC pattern, its dogmatic, thus the fat controller or fat model phenomena
评论 #19950833 未加载