HNHacker News
TopNewBestAskShowJobs

jeremyevans

155 karma · joined July 15, 2011

Ruby Committer. Author of "Polished Ruby Programming". Lead developer of Sequel, Roda, and Rodauth. OpenBSD ruby ports maintainer.
submissionscomments
jeremyevans··on Self-host your mail server
I've done the same for about 5 years (switched from SendGrid to smtp2go last year). I blogged about it when I first set it up: https://code.jeremyevans.net/2021-07-29-running-my-own-email...
jeremyevans··on PC Engine CPU
Actually, I think most had the code in track 2. Track 1 was an audio track warning you that the disc is only designed to a play on the system. More details at https://retrocomputing.stackexchange.com/questions/27518/did...
jeremyevans··on Ruby-refrigerator: Freeze all core Ruby classes
"freezer" was my originally desired name for this gem, but it was already taken.
jeremyevans··on Ruby-refrigerator: Freeze all core Ruby classes
It's cool to see this posted here. Refrigerator has been around for a number of years, but it doesn't get much press. It was originally developed as part of my work getting production Ruby web applications to run in chroot environments, where you cannot load libraries after chrooting (for more details, see https://code.jeremyevans.net/presentations/rubyhack2018/inde...). This allows you to emulate that type of chroot restriction without superuser access. It also allows you to detect monkey patches of core classes in libraries.

Note that it doesn't prevent or discourage monkey-patching, it just requires that you apply your monkey-patches before freezing the core classes. The idea here is similar to OpenBSD's pledge, where startup and runtime are considered different phases of an application's lifecycle. After startup, you limit what the runtime can do. With refrigerator, you freeze the core classes at the end of startup. So monkey patches are allowed during startup, but not at runtime.

jeremyevans··on A Replacement for Strong Parameters
There is a Ruby form library named Forme that works this way for Roda and Sequel (https://forme.jeremyevans.net/files/README_rdoc.html#label-R...). As you expect, this makes handling normal HTML form submissions much easier.
jeremyevans··on California is the only state to hide its spending – nearly $300B a year
That I cannot answer (not sure where that link comes from, maybe nonameiguess can tell you). Looks like suppliers.fiscal.ca.gov is a externet location for vendors that do business the state, not a public website.
jeremyevans··on California is the only state to hide its spending – nearly $300B a year
That's the most recent audited report. Auditing the state's entire financial report takes a long time. The report for year ended June 2020 should be published later this month (scheduled for December 22), according to the California State Auditor: https://www.auditor.ca.gov/bsa/aip
jeremyevans··on The Essence operating system at Handmade Seattle 2021 [video]
If you're using X, the fluxbox window manager supports tabbed windows: http://fluxbox.org/
jeremyevans··on UTC Is Enough for Everyone, Right?
> I'd just like to point out that a lot of RDBMSs support storing date and time alongside timezone information directly without using two separate fields. SQL Server has datetimeoffset, PostgreSQL has timestamp with time zone, and Oracle has timestamp with time zone.

PostgreSQL's "timestamp with time zone" doesn't store timezone, it converts the time to UTC and stores that, and on retrieval converts the value to the connection's time zone.

jeremyevans··on Government launches login.gov to simplify access to public services
That could be the case, but if you are going to open source the application, what would be the point of trying to hide it?

Considering that password hashes are stored in the users table, it seems unlikely. While you can use PostgreSQL to implement per-column permissions, it's a fairly large pain, and you have to make sure every query you are using that selects from the table does not select that column. Rails/ActiveRecord by default selects all columns in the model's table, and it's a fair amount of work to work around that.

jeremyevans··on Government launches login.gov to simplify access to public services
Restricting access to the password hashes using database security so that a vulnerability in the web application cannot expose password hashes unless a separate vulnerability in the database was also exploited. In PostgreSQL (and other SQL databases), this generally involves having multiple database users with separate permissions, making it so that the database user the web application uses doesn't not have SELECT permissions for the password hash column.

If you want an example for a Ruby authentication library that does this, there is Rodauth: https://github.com/jeremyevans/rodauth

jeremyevans··on Government launches login.gov to simplify access to public services
In case you are wondering how it handles password encryption and storage, it appears to use a custom password hash based on SHA256 and scrypt: https://github.com/18F/identity-idp/blob/980c2aa26397f530673...

Passwords appear to be stored in the users table in the "encrypted_password" column, and it does not appear that any database-based security is used. This is one RCE/SQLI vulnerability away from exposing the password hashes for all users. To be fair, that's probably true of most sites that store password hashes, but I would have expected better from 18F.

jeremyevans··on Rails 5.0: Action Cable, API mode, and more
That isn't a problem in Sequel, as you can pass a complex expression to #or, in which case it works as you would expect it to:

    Post.where(id: 1).or(Sequel.&({:id=>2}, {:name=>'Foo'}))
    # SELECT * FROM posts WHERE ((id = 1) OR ((id = 2) AND (name = 'Foo')))
jeremyevans··on Rails 5.0: Action Cable, API mode, and more
That doesn't appear to work:

    Post.where(id: 1).or Post.joins(:author).where(author: { name: 'John' })
    ArgumentError: Relation passed to #or must be structurally compatible. Incompatible values: [:joins, :references]
It appears that only the filter clauses are allowed to be different (similar errors if :select, :order, :group, :limit are different), in which case it's no more powerful than Sequel, just more of a pain to use. You can easily implement ActiveRecord's behavior in Sequel if you want to combine filter clauses for arbitrary datasets:

    ds = Post.where(id: 2)
    Post.where(id: 1).or(ds.opts[:where])
It's also interesting what happens if you mix where and having clauses (I'm not saying it doesn't make sense, but it may bite someone):

    Post.where(id: 1).or(Post.having(id: 2)).to_sql
    # SELECT "posts".* FROM "posts"
jeremyevans··on Is SQL pronounced "s-q-l" or "sequel"?
"s-q-l". It is ambiguous if pronounced "sequel". :)
jeremyevans··on Representing Trees in PostgreSQL
Not sure about ActiveRecord, but Sequel has supported using recursive common table expressions for loading all descendants in a given branch (or branches) of a tree for over 4 years using the rcte_tree plugin: http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Pl...
jeremyevans··on Roda – A new Ruby web framework
I looked into this and it is really easy to use, so I updated the website to use it. Thanks for the suggestion!
jeremyevans··on Roda – A new Ruby web framework
Thanks! I'll look into this as well.
jeremyevans··on Roda – A new Ruby web framework
I don't work on truly huge sites, my largest is only about 10kloc. But it scales very well for the all of the sites I've tried, and I think based on the architecture it would scale to much larger sites.

Your workflow with Rack->Ramaze should work similarly when using Roda. Roda scales down well:

  # config.ru
  require 'roda'
  Roda.route{'Hello world'}
  run Roda

There is probably some level of complexity where Roda may not be a good choice. I'm not sure what that level is, but I don't expect to hit it on sites I work on. In any case it's probably best to split up such an app into multiple apps/services before that level is reached.

In terms of battle readiness, it's new and currently I think I'm the only person using it in production. I hesitate to call something battle ready until there are more people using it, but I'm very committed to it and you can expect the same level of support for Roda that Sequel receives.

Thanks for the tip on embedded gists, I'll look into that.

jeremyevans··on Roda – A new Ruby web framework
The name Roda comes from the Ys video game series, in which the Roda trees play a small role. I'm a huge Ys fan.
jeremyevans··on Roda – A new Ruby web framework
You can do r.on('artist', :id) instead of r.on('artist/:id') if that is your style preference, both work in Roda.
jeremyevans··on Roda – A new Ruby web framework
Roda supports stacking apps via r.run to dispatch to any other rack app. You can also use the multi-route plugin, which allows you to split up the routing into subtrees, but keeps the current state.
jeremyevans··on Roda – A new Ruby web framework
The basic design for Roda was taken from Cuba (it's a fork of Cuba), and I think if you read the Roda source, you wouldn't find it difficult to understand.

There are certainly parts of Sequel that are overly clever, I won't argue that. But compared to similar libraries, I don't think it's worse in that department.

jeremyevans··on Roda – A new Ruby web framework
I'm glad Roda is finally getting some publicity. I submitted it here when it was released.

I've converted about 15 apps from Sinatra to Roda, and a couple of Rails apps to Roda (working on converting my final Rails app). Personally, I've found that the biggest advantages come when the URL structure mirrors your application structure, and you have redundant code in many routes, as that type of code becomes simpler, faster, and DRYer with Roda.

Yes, you can use a before block with wildcard routes with Sinatra, but Sinatra will still traverse the routing list sequentially and recheck the full route for every entry in the list. Unfortunately, while I love Sinatra, have contributed patches to it, and have used it since 0.1.0, the approach doesn't scale well for sites with a lot of routes.

The code non-locality issue shouldn't be ignored, and is probably the largest issue with Roda, but the issue is probably going to happen with any approach that DRYs up the code to the same degree. It's true if you use a before block in Sinatra, or a before_filter in Rails.

The use of a routing tree really isn't an innovative approach (at least not innovated by me). It's been around in Ruby since Rum was released in 2008 (and maybe earlier elsewhere). However, it's not well known, and I hope that Roda brings it into the mainstream.

One of the best things about Roda that I don't think has been mentioned in the comments yet is the plugin system, which I borrowed from Sequel. This makes it easy to extend Roda beyond its very small core. For example, the multi_route plugin makes it easy to scale Roda to larger sites by splitting up routing subtrees into specific files. There are currently about 15 plugins, and I have ideas for quite a few more that I will implement after finishing up my current Rails->Roda conversion.

I apologize that the code on the website isn't syntax highlighted. If anyone can offer their design skills, I would greatly appreciate it.

If you have any questions about Roda, please ask.

jeremyevans··on Lotus, a web framework for Ruby
Correct, it's not impossible, there was a proof of concept mongo driver: https://github.com/jeremyevans/sequel-mongo . I doubt it still works with current Sequel, though, as I only coded it for a lightning talk in 2010.
jeremyevans··on Give-and-Go with PostgreSQL and Sequel (RailsClub 2013 Presentation)
This is the presentation I gave at RailsClub in Moscow a couple days ago. It's a showoff presentation, so navigation is via keyboard (press z or ? for help), sorry if that makes it hard to read on a phone or tablet.
jeremyevans··on How Ruby Method Dispatch Works
This is a good introduction to ruby's method lookup, even if it isn't fully accurate. The author notes that he hasn't read the ruby source code, and his explanation is "just a model you can use to understand things."

While mostly accurate, his description of the module hierachy as a tree leads to a wrong understanding of how ruby's method lookup actually works. If ruby did use a tree, then including module B in module A after including module A in class C would result B being one of C's ancestors, which isn't the case. Ruby's method lookup uses a linked list (not a tree) using iclasses for modules (a pseudo-copy of the module, which is why later includes have no effect). However, a description of that may be too in-depth for an introduction.

jeremyevans··on The Development of Sequel
I'm sorry. The presentation was built with Scott Chacon's showoff library (https://github.com/schacon/showoff), which I assumed would handle cross browser issues well. I don't have an iPhone or a Mac, so I couldn't test it there.
jeremyevans··on Ruby 1.9.3 preview1 released
Nope. It was a new implementation by Tadayoshi Funaba (the ruby Date maintainer), but it uses a similar data structure to home_run, and performs about as well.