#RubyOnRails - 25 February 2019
« Back 1 day Forward 1 day »
[11:19:54] kidPalooma: Hello, I need a multilingual taggable system for my app. I am already using globalize and I like how acts_as_taggable_on works, particularly the ability to have multiple tag types. I've read https://github.com/mbleigh/acts-as-taggable-on/issues/755 but it looks like it leaves some regressions. Is there an actually multilingual tagging solution for Rails?
[11:53:09] nakuku: Hello. Is it bad to use `User.first` in tests? Like, i have integration test on POST /posts endpoint
[11:55:05] nakuku: But i've heard you should not use User.first in the test because you aren't sure if it's this record for sure
[11:55:53] nakuku: Personally i have a feeling that these are some weird rules made up to make one feel better but maybe someone can convince me?
[14:33:51] andywww: I’m having a bit of an issue with representations coming from rails/active_storage/representations after deploying a new release with capistrano
[14:34:42] andywww: but i can’t seem to find the directory structure in the app that I need to link with cap
[15:30:15] kidPalooma: Hello, I'm trying to override a class which is declared within a module in a gem in one of my initializers. When I boot my rails console, the module is not yet defined and I get 'uninitialized constant'. I am requiring the gem in my initializer and base modules are defined but this one is nested and I can't seem to get it to work. How do I make sure that the module has been loaded before I run my initializer's code?
[21:25:53] lunarkitty: I'm wondering if I should move everything over to webpacker on this new project
[21:34:47] Radar: (but more seriously: you can add certain directories to config.autoload_paths... but it is usually better to require files as you need them, and that way it's explicit about what's required where. Rails provides "require_dependency" for this sort of thing too -- it will reload things in between requests (iirc))
[23:03:02] Radar: Net: Because autoloading has caused me a lot of pain in the past. It will load things that I do not expect it to load. Whereas I can intuit the behaviour of "require", I cannot intuit the behaviour of autoloading because a lot of how it loads things is hidden from me.
[23:03:23] Radar: With "require" I know that there is a $LOAD_PATH. I guess with autoloading there is autoload_paths, but it still isn't as clear to me.
[23:03:39] Radar: Maybe recent React experience has tainted me where everything _must_ be imported at the top of a file ion order to be used.
[23:05:32] Net: I'm almost always in favor of explcitness, but I'm inexperienced with Rails autoloading and don't know problems
[23:05:48] Radar: Net: pain from incorrect constants being loaded. Most recently: we had a module in `lib/authorization.rb` called Authorization, but we also had a model with the same name (unknowingly). Autoloading loaded the model _first_ because app/models is higher up the autoload_paths than `lib` was, and so our module and its related code was never used.
[23:06:31] Radar: However, if we were _explicit_ about doing "require 'authorization'" we would've had this module loaded, and it would've conflicted with the model -- because the model is a class, and not a module -- so we wouldn't have had the exact same problems.
[23:06:54] Radar: autoloading is one of ruby's worst features in terms of POLS. It is constantly surprising to me.
[23:07:23] Radar: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/dependencies.rb#L459-L467
[23:08:16] Radar: that log line on 463 is new. I guess there is some sort of autoloading logging now in Rails master
[23:09:24] Radar: This most recent autoloading bug with Authorization took down production for us. It could've been prevented if we weren't relying on autoloading to load constants for us, and instead required things that we needed.
[23:09:46] Radar: Net: I think require_dependency does something to track that the file / constants defined by it need to be reloaded on requests.
[23:10:29] Net: What do you think about storing domain logic that doesn't fit nicely into the default Rails categories in lib/?
[23:10:33] Radar: https://github.com/rails/rails/blob/7d7372c14df4ad5b546f012a82538753c5991905/activesupport/lib/active_support/dependencies.rb#L237-L253
[23:11:37] Radar: Well, depends on what the logic does. In Exploding Rails (leanpub.com/exploding_rails) I advocate for classes outside of regular MVC, but I put them under app/ because they're a part of the application and depend on other pieces from that .
[23:12:46] Radar: app/transactions/projects/create.rb, where the constant defined is Projects::Create
[23:13:26] Radar: app directories are added to the autoload path. so projects/create.rb matches Projects::Create
[23:13:52] Net: I think I'd prefer lib/transactions/ so I'm not mixing design pattern grouping and semantic grouping
[23:14:58] Radar: I use dry-transaction there. All the logic for "transactions" in my application lives in app/transactions, and I can call that from wherever I wish. Controllers then primarily deal with requests/responses
[23:16:24] Radar: Yeah I can see the benefits of doing that. I think it falls apart in a Rails application slightly ... because of the Active Record pattern. There is no real clear separation between structs and database queries.
[23:17:10] Radar: In my most recent Rails (side) project, I've been using the repo pattern with rom-rb and it's working out really nice.
[23:17:22] Radar: Net: Yeah, most of the domain entities represent some form of data or another from a database
[23:18:16] Radar: AR does it too. But then it makes it easy to call out to the database whenever you want. N+1 happens in the view way too easily that way.
[23:18:33] Radar: But with rom-rb and separate structs that are actually not capable of making such database queries... well, the amount of footguns goes down
[23:19:57] Radar: Typically categorise them in terms of domain entity, but put them in directories corresponding to their ... function? app/transactions/projects/create.rb
[23:20:18] Net: That seems limiting to me. Do you encounter cases where you're not sure what directory a file should belong in?
[23:21:06] Radar: Not yet. I usually try out a few places and see what fits. If I can't decide I create a new directory. I don't have to live only within the bounds of what Rails provides. But still typically under app because everything else is there too.
[23:21:31] Radar: What I'd put under `lib` would probably be things that are pure-r Ruby, maybe they talk to HTTP endpoints to get back data. Or maybe 3rd party thigns.
[23:21:42] Net: For example, let's say you need to write some classes/modules to parse and write Excel files. Where would you put them?
[23:22:28] Net: What if (for some unimaginable reason) they need to rely on app models or transactions or repositories
[23:23:28] Radar: The things then passed into the ExcelParser come from the models. ExcelParser wouldn't know how to fetch those things itself.
[23:25:29] Net: What if you had an Excel file model that you wanted to use to represent Excel files after they're parsed and before their written?
[23:26:34] Radar: It's a class that encapsulates business logic of a particular data struct. So probably app/models.
[23:26:52] Radar: The parser isn't a model. It acts on models. It would go into lib/excel_file/parser.rb.
[23:28:32] Radar: Guessing the file is uploaded somehow. I might wrap that logic in a Transaction class. It accepts a file, then passes that file to ExcelFile::Parser, which returns a Hash of the data. That Hash then gets passed to ExcelFile to get turned into a proper object.
[23:30:11] Radar: You could argue either way. I can see the merits of either returning a Hash or an ExcelFile object.
[23:30:54] Net: When you said "I think it falls apart in a Rails application slightly ... because of the Active Record pattern. There is no real clear separation between structs and database queries.", what did you mean?
[23:31:43] Radar: same as I said previously: traditional rails models combine database querying, business / domain logic all within the same class. Your business logic can either intentionally or unintentionally make further database queries. This is the #1 reason of degraded performance in every Rails app I have worked on.
[23:32:07] Radar: By making "accidental" database queries harder by making the classes simply represent the data + business logic, you can prevent this sort of problem from occurring.
[23:32:46] Radar: Structs == simple classes representing data returned from a repository. In the repository pattern there's one extra layer between the model + the DB and it makes _all_ the difference. The same pattern Ecto follows. You probably know it already.
[23:37:37] Net: I'm imagining a pattern where models handle DB queries and simple data holding, but where most buisness logic has been moved out of the models to other classes or modules that reside in lib/
[23:40:37] Net: So the models are simple value-holding entity representations—usually tied to a db table—which are acted upon by more conventional logic outside of rails patterns.
[23:42:18] Net: I'd like to treat app/ and certain patterns in it as building blocks for more conventional, less pattern-oriented code.
[23:42:54] Net: It's rare to find people who think this is a good idea, which makes me think it's not.
[23:44:11] Net: sometimes feels that way, but it's less arogant to believe I'm just not in the Rails mindset