Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
An Overview of Ruby on Rails 7.1 Features. Part III (archive.org)
92 points by mariuz on Jan 23, 2023 | hide | past | favorite | 94 comments


Rails has matured through the years, I'm convinced it's the right framework for any project if you already know it, you can get by with Hotwire for the FE and not run after React and the rest. Happy to be a Rails dev to be honest.


Rails is extremely easy to get started with but after a few years the lack of types on Ruby cripples every single Rails app I've ever worked on. You can have as many unit tests and browser automation tests as possible, but updating any gem is a dice roll despite doing as much due diligence possible. And it's always something extremely trivial like a method changing its parameters without announcing it in the change log for some reason. Something almost any other language would warn you about.

I've been doing Rails dev for 7 years now but I just don't see it winning over TypeScript/nodejs frameworks. The only advantage Rails still holds is the out of the box batteries included package. But once a TS framework gets this, Rails will be in decline.


> Rails dev for 7 years now but I just don't see it winning over TypeScript/nodejs frameworks

I think you're comparing a language/runtime with a framework here. I also prefer Node and JavaScript over Ruby but I get what you say, and I agree.

I think Adonisjs ticks all the boxes to be that framework in the future. It just doesn't have the community it needs to be 100% successful yet... with more adoption it will get all the missing features, documentation and little annoyances it might have today polished.

But something I'm worried about is if that the fragmentation is just too big at this point. I don't see people agreeing on a single "full stack" framework as it happened in other environments.

I think this happens because most other "big frameworks" were born when there were not that much competition and not that many people on their ecosystems, so there were a lot fewer options and people concentrated around those frameworks and made them grow to what they are today (Laravel, Rails, Django, Spring...).

The "backend JavaScript" ecosystem is a freaking mess. So many competing options, all of them terribly incomplete, all of them claiming to be "full stack" just because they can execute JavaScript on the server... yes, maybe "full stack" but without the battery... it's a lamborghini that you have to put together yourself before being able to use it.


This is exactly why I’m keeping my eye on RedwoodJS. They are coming for the crown.


Same thing that other people sat about Next.js, about Remix, Nest, Qwik, and the other 10 thousand that "are coming for the crown". In fact, that's the problem.


Doesn't Ruby have 2 production-ready typecheckers now? I think Ruby officially has something called RBS, and Stripe open-sourced Sorbet.


Used to work at a Rails shop, and led an effort to get type safety into the codebase. It was a nightmare that wasted endless time and added plenty of stress.

Sorbet is great on vanilla Ruby code that doesn't try to use too much arcane metaprogramming. It's "okay" on vanilla Ruby code that uses some arcane metaprogramming that humans can reliably reflect in RBS files. In a Rails codebase, which is (IMO) a huge ball of relatively hard to statically analyze magic and quite heavily uses all sorts of tricks for either API ergonomics/skimmability or for performance, it was a mess, and frankly, I had a pretty nightmarish time selling almost any of the feature set beyond (1) ADTs/Enums (2) the subset of Interfaces as exposed by `T::Struct`.

Sorbet is a herculean effort by some extremely talented devs. I don't at all want to discredit that. Tapioca is likewise an impressive DSL-reflection machine on top of RBS files, particularly post-0.8 release. But type safety in a Rails app is, at least in my experience, extremely high cost both upfront and maintenance.


To offer another point of view: I work on a recent Rails app that was set up with Sorbet/Tapioca from the get-go. All Ruby code is `# typed: strict`, and we (I) feel like the ROI is generally positive. It's caught more than one bug, and it's easy to eject from it when it gets in your way.

That said, type safety via Sorbet/Tapioca is ultimately an afterthought in Ruby and the DX suffers from it compared to languages where type safety is baked in. In my limited experience, MyPy in Python was even worse though.

As for RBS, I have literally never seen it used in the wild and I don't know why the Ruby core team bothers with it rather than go all-in on Sorbet.


(your comment made me realized I kept typing "RBS" when I meant "RBI" in a Sorbet context. oops)

Anyway, I did have my strong suspicions that Sorbet would pay off more in a codebase that used it from Day 1. Glad to hear at least one report that indeed, that was the case.


They are terrible. Typescript might have spoiled me, but the type system is bad and the type checkers are even worse.


We evaluated them, it's just not there and it's unclear if it ever will be. DHH, the lead for the Rails project has indicated that Rails will "absolutely not" have a type checker in reply to a tweet asking about it. And a huge amount of work would be required from the Rails team to get type checking to work.


I've worked with a lot of Rails code bases over the last 10 years and just haven't ever experienced this problem from a types perspective.

Certainly, if you let gems start to get out of date the dependency chains to get them updated can become a task but that's fairly true of any language. It's one of the selling points for moving parts of an app to isolated services too.

Everything is a tradeoff though. I don't know that you can get the Aspect Oriented Programming gains that you get with Ruby and Rails with a more strictly typed language.


Every Rails upgrade is kinda proof of the problem, isn't it?

There is an entire market on Google of companies expert in upgrading Rails, that to me is a bad signal.

(notice, I have almost 15 years of experience with rails)


During the Ruby 1.8.7 to 1.9 transition there was a lot of complexity to things, but it hasn't really been a big problem since then has it?


I dodged that, started getting serious with rails 3 and ruby 1.9+

No,there are still many undocumented breaking changes. I recently upgraded an old app from Rail 4 to 7 that used minimal non-rails stuff and was shocked by the corner cases.

Manu changes to activerecord api go completely undocumented, but they break the code nonetheless


Did you go straight from 4 to 7 or 4, 5, 6, 7?


There is no upgrade guide from 4 to 7,so I did from 4.2 to 5,from 5 to 5.1, from 6 to 6.1 and then to 7.

I actually found a bug that broke my app at version 6 that was resolved in 6.1,so technically my tests were not passing in version 6 and I did an "unsafe upgrade" to version 6.1


It's good with React too when you need more interactivity.


I believe you can do anything React can with Stimulus + Turbo these days. I don't do much FE but I've been tracking Hotwire for some time now.


Maybe you can with heroic effort, but you shouldn't. You should build within the constraints of your tools. HW + Stimulus are great - good enough for what most web apps need to do. It gives you "traditional web app, with a bit of realtime updating" - which is the perfect fit for most web apps.

But you wouldn't want to use it for a fully interactive desktop style application with lots of interacting components.


Agree. So unless you have a pretty big budget and you're building Google Maps or Figma you shouldn't use React.

Sadly, everyone things they have such a big budget and they're building the next Figma. Even if you're building a CRUD app. (I'm talking to you previous team of mine).


You can do anything with plain JS too, but that doesn't mean you'd want to. The problem with Hotwire is that you do often have the server round trip in there. That's fine most of the time, it just gets a little harder to understand as the complexity rises. That's not to knock it, I think Hotwire is pretty good.


In what scenario would complexity be higher in a simple UI - server loop? Doesn’t complexity usually arise from having additional logic in the browser and maintaining state separately?


I guess it depends somewhat on how you imagine up something and write it. I was working on some drag and drop UI that had multiple sortable lists and an action area. Figuring the server side and UI at the same time didn't work out. I reversed and implemented the UI with its required state, and then it was easy to transform that state to what the server side required, and vice versa.

Complexity is tricky. Are three simple things more complex than one thing thats harder to understand?


Still decent amount of caveats given the UX expectations of 2023... eg last I checked there was no official support for transition animations


Yes, but there is a whole ecosystem of react components and react developers.


perhaps for most things but probably not to the extent of something like excalidraw, which uses react


You can still use React or whatever on those pages. And for the rest (settings pages, signup pages and all the CRUD pages) you can use standard Rails with Hotwire.


Yes, but in that case, you can use only the complexity where you need it, instead of globally.


So many great features. Rails still seems to be the best choice to build a web app.


Completely agree with you! It's kind of an interesting time because my current Org is moving away from a large established Rails codebase - and it makes sense given needs. But Rails is still such a good option for building web apps. It will definitely stick around

Edit: i really like seeing "overview" posts like these to get up to speed on new features because many devs seem to rarely work on "up-to-date" versions


Just curious, I'm not into Rails or Ruby at all, but given an established codebase, what's the reasoning for a big move like that? My org is doing a similar shift (C#, the legacy .NET Framework -> Elixir) and while I quite like Elixir I don't think the language change itself is doing much for us.


Wish I was more aware of the decision making process for everything but believe the move is to foster more of a micro frontend architecture where separate js packages/federated components make up the client experience. The Rails side of things is really used as an orchestration layer for the views and to handle business logic while also consuming a .NET database layer for services.

It's not really the "normal" way of using Rails but seems to function quite well on a "large scale". I agree it's probably not just the language change itself that's the reason but also due to the agility/advantages of Node compared to a Rails "monolith" - and I'm already starting to speak outside my familiarity of the architectural goals of everything


Interesting, thank you for the context. My company's current system is simpler in nature I think (three web servers processing internal and external requests, one DB server, one app server handling everything else, and that's our problem) and scales not at all. We're going from one monolith to another, but set up in a way that can be scaled out arbitrarily, and overall more flexible and robust.

Generally I'm interested in stories of these big do-overs because it hasn't been the smoothest of sailing for us.


I think if you have a sufficient number of staff for a particular project, it makes sense to rewrite parts of it now and then to gain a better understanding and also the chance to do things without making the mistakes of the past.


I have a question and anecdote.

I’ve been on teams in the past that had to deal with rails apps (legacy code usually) and I found ruby to be really difficult to understand. There are so many ways to do one thing, and with the rails addition there are now so many conventions to follow. Then when those conventions don’t work anymore, and the code base goes off the rails (no pun intended) and the out of the box conventions no longer make sense.

Granted most of my experience is writing Go, followed by dart, swift, and typescript. I have a hard time navigating codebase of a dynamic language and it’s a pita to have to rely on tests (not everyone writes good tests).

I use Go for all my backend tasks and it is not only fast performance, but really easy to be productive in because there is usually one way to do things and the std lib is amazing.

Where does rails fit in? Like I can build an entire production ready backend service that can scale in like 2 days with Go that is easy to deploy and maintain, and not need to bring in any big Go framework or libs besides like uuid, managed sdk, or db driver.

Why would someone choose rails over Go or even node JS with express and a few middlewares? (In 2023)


Advantages of Rails over Go:

1. REPL. Huge. You can be insanely productive with it. If you're integrating with APIs and therefore dealing with complex nested data structs, you can explore them live. You can explore what's possible with any lib, try things before you write any code. You can also debug errors on the fly as soon as they occurred, right in the browser.

2. Your app is organized around entry points by default. Nobody knows the proper architecture up front for a brand new application. Rails gives you rake tasks for CLI, controller actions for web requests, ActiveJob as a convention for background jobs. You can grow your app's inner architecture over time, but you got all the entry points laid out up front, and they rarely ever change.

3. A lot of built-in security risk mitigation. Cross-site request forgery, encryption for cookies and sessions, convenient encrypted configs and secrets, log filtering functionality, escaping everything by default, and many more. Everything is already handled out of the box.

4. Veteran open source packages (gems) with large companies sponsoring maintenance. Decades of dev and polish on most needed gems, still going.

5. Analytics and monitoring out of the box. Completely wired for tracking performance of everything out of the box. No need to manually integrate performance trackers, just one-line install and you have full profiling capabilities of every part of the app, with many popular dashboard services.

6. Error monitoring out of the box. Many ways to notify exceptions via chats, email, and services, with typically zero integration work.

7. Completely thought-out testing environment out of the box, for both integration and isolated testing. Clean slate on every test without manual setup.

8. Lots of Ruby and Rails tools/functions (e.g. Enumerable) for transforming data via functional pipelines (select, reject, tally, map, take_while, etc) out of the box.

9. Ability to write incredibly reusable code to solve a problem for all data types, not just one particular type (this has gotten better in Go with generics).


Thanks for your deep rely, I appreciate it.

A lot of those things make sense to me and I can see why people would prefer to use a framework like that.

I guess for me, I already know what a web service needs like adding CORS, setting up csrf protection, cookies, logging, etc. so its trivial to add that to a project whether its Go or Node or whatever. Conceptually I know what is required. As for project structure clean architecture has helped me basically not have that be an issue.

I guess its a matter of trading high performance and robust scaling for developer convenience. Like I said to another comment, I probably won't ever use rails but I understand now why people use it. It is probably good for teams that have "fresh" employees like folks out of college or something to quickly be up to speed without having to hand hold too much.

Thank you for taking the time to explain your points.


> clean architecture has helped me basically not have that be an issue

If you setup your Go app structure like a Rails app structure (basically what clean architecture is), then you have it covered. However, I believe you do have to set it up by hand each time in Go, or write your own generators.

> It is probably good for teams that have "fresh" employees like folks out of college or something to quickly be up to speed without having to hand hold too much.

Architecturally speaking, yes and no. Rails does a lot of non-obvious (to new devs) things for very good reasons, that these devs would have to spend quite a bit of time to understand. Try to write Rails without knowing all the wheres and whys, and you will quickly become frustrated. In Go, you can kinda guide new devs along as you build out most things from scratch. Both of these situations require guidance from experts.

Syntactically speaking, the opposite is true. Ruby lets you write incredibly expressive code by giving you nearly limitless flexibility. In newbie hands this could become a disaster.

It's a common misconception that Rails is beginner-friendly. Its authors have been trying to correct the record on that, by using sharp knife analogies. You have to be very careful with Ruby and Rails, since there aren't nearly the same guardrails as you get with Go.


Thanks again, love the info!


> so its trivial to add that to a project whether its Go or Node or whatever

The thing I think you're missing, is that it's trivial TO YOU to do this, and of course you will understand it end to end and be supe productive.

What happens when more people join you to work on that project? What happens when you leave and the next developer needs to understand all of this? What if he doesn't agree in the way you did things? Did you write thorough and detailed documentation for all the decisions you've taken? Can you guarantee it has no security flaws? What if the translations library you've picked has gone unmaintained because the developer that was building it as his side project got something more interesting to do on their weekends?

That's the problem. Ending with a custom snafu that once made sense to somebody. Of course this can be made, and of course the next developer can pick it up, refactor, improve, etc.

But from a business point of view it just makes literally zero sense. Think about all the time (and thus money) spent integrating things or writing your own infrastructure code and documenting it (because you're documenting it right?) and testing it (because you're testing it right) that could have been spent on actual business code.

Compare that with the situation where you've just picked Rails/Laravel/Django/etc. The next developer knows what to expect. Knows how the most important parts work, has tons of documentation and material for learning, and when applied to the position they already knew more or less what to expect.

The benefits of a "batteries included" framework is not the framework per se, is the community around it.


Elixir also fits every one of those points plus OTP. I think even Spring Boot matches those advantages, except for a working REPL. Or is there a way to use JShell on a running app? I don't know. But Spring Boot apps are super quick to get started on. Much faster than Rails in the boiler plate department.


> and I found ruby to be really difficult to understand

This is my one pain point with JS actually. I've tried getting comfortable for literally years. Sometimes when i look at how stuff is done in JS, it's so incredibly alien to me. I just can't wrap my head around what is happening.

I was hoping it would go away with time. Unfortunately it doesn't. Maybe it's the "flexibility" of the language or something.


imo JS is one of those languages that is hard to master. It has quirks, and there are a lot of ways to do something just like ruby.

Whenever I have to use typescript, I use es6 classes with static methods on them. Helps me keep no internal state and everything is organized.


Ruby on Rails is designed for making entire websites, not just small services. It has a massive amount of built-in libraries, integration, and a rich plugin ecosystem for that purpose.

If you wanted to write a small backend in Ruby, you would typically use Sinatra.

So you’re comparing apples to orchards. :)


Yeah for sure. It comes with a lot of things. But all that comes at a huge cost.

You can use Go for making websites (its a general programming language) in fact we use it for exactly that. You can render templates easily.


I can build a backend service that can scale in 1 day with Rails.


At what cost?


Just their 1st born child


A hefty price to pay.


Use whatever you want!


Ruby is OOP.

Go is procedural.

They're different.


I know.

I'm asking why someone would choose rails to build software (a company) than something like Go which is IMO easier to learn and way easier to actually manage.


Ruby provides a complete hackability/customization framework for you to use. So library locked-in is out of place.

For example, you use a library which gives you 99% of functionalities you want. Now there's a 1% use case you want different behaviour and you can't directly modify library code. There's an escape hatch here, it's Ruby. It's like "fork" on steroid.

Why Rails ? Because it's the "only" web framework in Ruby. No second choice for large scale application.


thanks. one more question -

from a cost perspective, again I'm not super experienced in rails but enough to debug production issues and ensure stuff works -

I recall that for this one rails application, there were like 30 instances of it running on some beefy configurations and it was getting hammered quite a bit. We saw it was only able to manage like 300 req/second. A lot of time was spent rendering the template, like a few ms.

I ported that thing to Go and it takes microseconds to render a template. A single Go application running on cheap, shared configuration can handle like 10x the traffic.


The de-factor Ruby/Rails way to application development is DRY. DRY everything if possible, performance is not 1st priority.

Less code >> more performant in general use case.

TL;DR is: Vendor lock in vs performance lock in. It's hard to not have both at once.


Ah I see. How do rails-first places handle performance issues, such as this template rendering issue? I'm curious to know what I could have done differently than a re-write.


Caching. There are multiple layers of caching in rails, including caching of rendered views/partials.


The Rails way to scale is caching. In your case, Rails has something called Fragment caching.


I see. But that would increase memory usage no? I'll look into it, thanks. And I understand now, the priority is not to chase high performance but have some set of standards that you can adopt without to much bike shedding.

I still am not convinced to use rails over Go for my needs, but I am glad you helped me get some more insight.


FWIW, my experience on projects with a rails backend is it makes it really easy to fall into performance traps. Active Record is especially bad at encouraging N+1 queries, though the same could be true of many ORMs.

A second issue is that if you come from a background where everything is either explicit or obvious, you are in for a world of hurt. I've seen senior developers try to figure out where a particular method is defined by setting a breakpoint, connecting a REPL, then invoking some special methods to get Ruby to tell them the file and line for the source definition.

It is just a different way of developing, and (personally) I think the reputation is a bit cult-ish.


Easier for you is hardly easier for everyone.


RoR is nice, but it lacks one of the most important abstraction layer: The schema layer for HTTP. Currently the default is to mix model params with http params. It's bad default.

Of course you can use dry-schema for that purpose, but i do think the framework should enforce that for the whole ecosystem to follow.


Yeah, the whole permitted params is actually is pretty shitty workaround against something else.

We're missing the 'form' part. Validations should be done against forms, not models. Default forms can easily be derived from models, which is nice for simple apps, but this is really something that's lacking in rails.

Permitted params exists because there is no form (dry-schema for example). There's ActiveModel, but it's not the same, and it's not ad-hoc / bound to the view/controller layer of things.


I inherited a project where all the validations were in the forms and it meant that you couldn't reliably use the model layer without the forms layer (you'd end up saving invalid data). We eventually moved the validations to the model layer and dropped the forms abstraction. It didn't feel like the right separation of concerns when we had to pretend data was moving through forms to reliably interact directly with the model layer.

The enforcement of allowed params (and type casting from strings) definitely seemed like it was in the right place per-action in the control layer though, so we kept that from the forms even though we implemented it in the controllers.

I wonder if we just didn't understand the idea though? Or maybe if the original implementers didn't implement it right?


It's the main reason for bad legacy of many of Rails applications in the wild (noone wants to maintain the model code inside the view/controller). And it's HARD to understand why ? Omasake is bad omasake when you mix "unrelated concerns" together.


Sounds like you want MVVM vs. the default MVC pattern Rails ships. I think there are a few options out there which are bolt on for Rails but nothing out of the box.


permitted params and validations are two different things though.


I've had great success building form objects with portrayal (https://github.com/scottscheapflights/portrayal) and ActiveModel. You can put validations into them, and auto-filter the params by making a `from_params(params)`-type constructor. In it you can call require/permit with `portrayal.keywords`. You're right that it'd be nice to have this out of the box, but this is just a few lines of glue code to setup. I'm in the process of making a new app template that does that.


This gem is just for construction, no validation ?

Schema layer purpose is to enforce invariant at the boundary of HTTP.


The gem is just for declaring struct keywords (slightly more featureful than vanilla structs). Validation is left up to ActiveModel::Model. I would do a setup like this:

    class ApplicationForm
      extend Portrayal
      include ActiveModel::Model

      class << self
        def from_params(params)
          new(**filter_params(params))
        end

        def filter_params(params)
          params
            .require(model_name.param_key)
            .permit(*portrayal.keywords)
            .to_hash
            .transform_keys(&:to_sym)
        end
      end
    end

    class MyForm < ApplicationForm
      keyword :first_name
      keyword :last_name

      validates :first_name, :last_name, presence: true
    end
Can use it in a controller action like

    form = MyForm.from_params(params)
    if form.valid?…
      # the usual
One of the good things about this approach is that you can also use this object in form_for/form_with in your views.


Have you looked at ActiveModel::Attributes ? That coupled with ActiveModel::Model makes for simple form objects quite nicely. Also, you can write your _own_ ActiveModel::Type so you can require that a particular attribute is a particular (business) model. I've been finding it a very nice way to write form objects.

It's a bit dated now, but, I did a short presentation for my local ruby meetup and the slides are here [1]

1. https://slides.com/patrickdavey/rails-5-2-attributes-api#/25


Thanks for the suggestion. I actually explored switching to Attributes for a new Rails app, but 3 reasons made me come back to portrayal gem: 1) attributes don't support defaults. 2) I prefer not to set types on form object attributes, since they are supposed to deal with messy user input. Instead I lean on validations. And 3) I like read-onlyness, freeze, equality, duplication, and introspection features of portrayal gem.


Attributes do support defaults. You can absolutely do:

   attribute :my_time_at, :datetime, default: -> { Time.now }
   attribute :persisted, :boolean, default: false

What I like about the types is that it will automatically coerce the messy user data automatically (this is what AR is doing under the hood anyway right?), you can just be more intentional about it.

Anyway, glad you're happy with portrayal :) I definitely agree with you on the "freeze, read-onlyness" etc. being good things to have!


Ah, I accidentally lied by trying to reconstruct a vague memory, apologies. Now I'm remembering it in more detail.

It wasn't lack of defaults, it was handling of defaults. Portrayal does a couple of smart things like evaluating defaults in a specific order in the correct context (while still only evaluating once), such that this becomes possible:

    keyword :name
    keyword :greeting, default: proc { "Hello, #{name}" }
I like being able to do this. (This also works gracefully with subclassing.)

The coercion argument is good, but I'm not a fan of doing it implicitly. (This was the real counter-argument I should've made). I prefer to have a single place where input is entirely processed, such as a `from_params(params)`-style constructor. In that constructor you could either coerce, or do anything else with the input prior to passing it through to `.new`.


That said, there are similar objects one can make without using the "form" moniker, for API submissions for example. Granted, I also wish a solution was built-in.


I also wasn't a fan of how Rails handles params, so I ended up writing my own lib. And I'm actually working on open sourcing it and extracting into a gem.

    typed_params {
      param :data, type: :hash do
        param :first_name, type: :string, optional: true
        param :last_name, type: :string, optional: true
        param :email, type: :string, format: { with: /@/ }
        param :password, type: :string, length: { minimum: 8 }
        with if: -> { current_bearer&.admin? } do
          param :metadata, type: :hash, allow_blank: true, optional: true
          param :role, type: :string, inclusion: { in: %w[admin user] }, optional: true,
            transform: -> (_, role) { [:role_attributes, { role: }] }
          param :permissions, type: :array, optional: true, if: -> { current_account.ent? } do
            items type: :string
          end
        end
      end
    }
    def create
      # ... controller code here
    end
Each param schema has to be defined by source, e.g. request body vs query string. And params aren't intermixed (including routing params).


I'm very ambivalent about Grape, but this very much reminds me of something I do really like about it: the param validation. https://github.com/ruby-grape/grape#parameters


Yep! I was very inspired by Grape’s param system.


We want a generic interface: Think Rack for params parsing/serializing, then you could easily parse any params into your own data structure. Stringly types are out of scope.


Why do you need something so generic? Can you share a use case?


Yeah, I'm pretty sure every Rails shop has invented some flavor of APIObjectSerializer based on JSON-API, REST, or whatever because doing it ad-hoc will make you pull your hair out.


Maybe this is a bit close-minded to say.

Even with the evolution of Ruby on Rails and adding more rich feature sets, I wouldn’t recommend it as an out of the box Webapp BECAUSE upgrading to newer versions of RoR sucks.

The more time I invest in trying to like RoR the more I end up having to fork gems to patch them because upgrades cannot be made smoothly.

It so easily integrates ActiveRecord, and heavily encourages it, that when you want to pull out of using it it’s a huge pain.

Test suite combines unit and integration testing.

It’s been a net loss imho to learn and work with it over the years.

I’ve been waiting to be persuaded otherwise.

Edit: apparently people disagree with me but haven’t countered the points, is HN just full of Ruby fans?


I've never had problems with upgrades, in fact the latest version of Rails make upgrading a breeze. What Rails app version are you trying to upgrade? Happy to help. Rails also has an upgrade guide that's quite good: https://guides.rubyonrails.org/upgrading_ruby_on_rails.html

And you can use https://railsdiff.org/ to check what you're missing in upgrade apps. Anything other thing that breaks would most like come from another gem, which doesn't make it Rails' fault or Ruby itself, in the case of Ruby, you can track everything to the source to fix it. Ruby keeps a change log diligently. Everything is trackable, at least in my experience.


I've upgraded our moderately sized app from 3 to 4 to 5 to 6. Haven't gotten to 7 yet. This is widely accepted to be one of the most painful parts of rails, so I'm surprised you haven't had a problem. Maybe you've only upgraded small apps, or maybe only upgrade very recent versions (they are getting better). There are whole consultancies dedicated just to this task. Github and Shopify post about dedicating whole teams and tools just to the task.

Even with very high test coverage on a large app it is a huge and high risk effort to upgrade - there are so many deprecations and unnecessary behavior changes. The `belongs_to` now validates presence was especially egregious and arbitrary. Of course you can turn it off with a variable - but now we have a rails app that is a mix if defaults from 4 different versions of rails.


It's hard to counter "it sucks" and other rather vague points like the ones you've made.

> upgrading to newer versions of RoR sucks

This hasn't been my experience at all. Rails comes with a built-in tool that interactively helps you upgrade your app `rails app:update`. Even on a 300k+ line Rails app I work on, our last major Rails upgrade took a single engineer about a week to do. It could be better, but it's one of the easier frameworks to upgrade, in my experience.

> The more time I invest in trying to like RoR the more I end up having to fork gems to patch them because upgrades cannot be made smoothly

Isn't this the case generally? Dependencies are liabilities. Not sure why this is a problem with Rails?!

> It so easily integrates ActiveRecord, and heavily encourages it, that when you want to pull out of using it it’s a huge pain.

ActiveRecord is a central component of the Rails framework. Why would they encourage you to use an alternative?

> Test suite combines unit and integration testing.

I think it's first important to state upfront: there is no single canonical definition of "unit" or "integration" tests. I assume your point is that the standard unit test examples in Rails hit the database? That being bad is, like, your opinion, man. And you totally can decide to not design things that way.


This is because Rails does not have a strict backwards compatibility policy like many other frameworks. It's done on purpose to stay relevant, aka "Progress over stability".

https://rubyonrails.org/doctrine#progress-over-stability


That would be fine, if it was possible to actually work out what changes you need to make. But Rails will have breaking changes every release that aren't mentioned in the docs. I've spent around 200+ hours over the last year trying to update our app from 5.1 to 5.2. And it's not some kind of megaproject on the scale of Github, its an ordinary app around 10 years old.

Every single Rails update is extremely painful and issues will slip through every unit test and browser automation you can come up with. Stuff that would be trivially catchable with type checking.


I would say the most annoying bit is around javascript. For example I would like to move a rails 6.1 project to 7, and also replace webpacker with esbuild. I'm pretty sure I will just create a fresh 7 project and start copy pastaing files over, then do the javascript stuff delicately (the default javascript setup in rails 7 is also quite strange)

But upgrading pure API Rails projects is much less painful


The Webpacker removal in particular was a huge pain for me. I was deeply frustrated by DHH’s belief that the framework no longer needs to support TypeScript.


Not sure why you're downvoted either, it's a legit concern. One way to address it is by being very conservative and picky with gems. A good example is Hey's Gemfile (the app made by Rails creators): https://gist.github.com/dhh/782fb925b57450da28c1e15656779556. It's a good (albeit slightly outdated) example of not straying too far from defaults, while not reinventing the wheel either.


You have to be super careful with gems because every single one you add risks blocking you from updating rails. Resulting you either having to wait for them to get updated, or if they are abandoned, you have to remove them and rewrite all the code that depends on them. I've spent so long replacing all the code in our app which is built on abandoned gems.


I agree you need to be careful to only add high quality gems - but that holds true for the deps for any project.

You can also fork/vendor the gem and fix it, vs rewriting the whole thing from scratch. If a gem is abandoned you don't need to nuke it - you just take ownership of the code. Essentially if you use a gem you are saying "this code is as good as our code" so just maintain it just like it is your code.


True. I tend to stay away from gems that try to integrate into multiple parts of your app to provide some sort of comprehensive solution. The kinds of gems I recommend are: 1) libraries (you call into them when you need them) 2) mounted apps on a url, isolated from the rest of your app 3) generators (a nice example: https://github.com/lazaronixon/authentication-zero).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: