Manage module trees with ActiveSupport - ruby-on-rails

I have a Rails project MyApp which I fragmented into multiple gems. One of them is to manage users.
Considering that I want code reloading and auto-require from ActiveSupport, along namespaced folders to require files. I can organize my code this way:
# MyApp::Users
./lib/my_app/users
./app/controllers/my_app/users/
./rspec/unit/my_app/users/
The above way is the most clean one, but results on long nested routes with the repeated pattern my_app/users/, which can be exhausting for lazy programmers. Since I still need the folder namespace to differentiate code from different gems, I thought about abusing the root namespace:
# Users
./lib/users
./app/controllers/users/
./rspec/unit/users/
That is not as clean and the more I fragment into gems, the higher my chances to have a namespace collision.
Which organization pattern is the most commonly used? Which is the Rails way?
For a library the first one seems the best one, but for a large application it feels tiring having all the time long paths and maybe the fear for name collision is doing more harm than good.

Related

Is it a good practice to namespace jobs?

Is it a good practice to namespace jobs?
In my application I have two jobs that are related to the Page model - both of them are going to receive a post_id and perform a specific task there. The jobs are called PageWritingScoreJob and PageArchitectureScrapingJob. I want to use the namespace Page instead: Page::WritingScoreJob and Page::ArchitectureScrapingJob, but not sure if that's a bad practice.
thanks
There is no real reason why using namespaces would be a bad practice.
In Rails apps everything is generally lumped in the global namespace not necessarily because it's the best way to do it - it just convenient.
It's a widely accepted that placing code in the global namespace is problematic when it comes to interoperability as it greatly increases the risk of name collisions. This is especially true in Ruby which lacks a import system like that in Python or Ecmascript. That's why almost every gem incapsulates it's constants in a module.
In a rails app though you are most often the end consumer of the application code which means that placing your controllers and models in the global namespace works well enough that it's often worth the trade-off of simpler code templates and not having your code intended an additional step and nested in an additional folder.

My Rails Engine depends on my parent app

I want to use Rails engine to modularize my current app. I have read a number of articles about engines including TaskRabbit's and Pothibo's posts.
I have a Rails app where I want the parent app to contain all the user tables. The engines I want to mount in the app will be dependent on the parent app, which contains all the user models. While I have this working, I'm unsure as to whether this is bad practice, as my engine will be unable to run without the parent app. The main idea to do this was to modularize the code. While Pothibo's article suggests namespacing within the same app, I like the freedom of managing a separate codebase altogether. Would appreciate some advice as to best practices.
In my opinion there are two major use cases for Rails engines:
1) Reuse functionality in multiple applications. This is the most common use case.
2) Provide a migration path to split a monolithic application into smaller apps (micro services). You can for example start by splitting them out into an engine in the same git repository and mount them by using gem 'xxx', path: 'engines/xxx'. Then later split out further to separate code repositories and/or host as a separate application.
Generally I would advise against no 2, unless the application is big enough to allocate the different engines to different teams. Disadvantages would be things like complications when you have dependencies between different engine code bases or db tables. Advantages are things like less tests to run, less code to take ownership of, etc.
You might find these interesting:
https://github.com/EPI-USE-Labs/activesupport-decorators
http://pivotallabs.com/leave-your-migrations-in-your-rails-engines/

When should you nest model declarations in Rails?

What are the guidelines about when it is better to nest Model name spaces and when it is better to leave them all top-level?
For instance, when I have a few classes that all have something to do with one core class (and the majority of the system only deals with that core class) then my instinct tells me to declare them as such:
CoreModel
CoreModel::DependentOne
CoreModel::AnotherDependent
Almost always this corresponding to has_many/belongs_to relationships (i'd almost consider this the next candidate for convention over configuration.)
And again, my routes often reflect this nesting:
/CoreModels/:core_model_id/DependentOne/:id
The reason I feel like I should do this is because often two component areas of the same large application may need a supporting component with similar if not identical names as other areas of the software. I feel like name spacing these dependent models (which only exist to support that core model) is the best way to go.
I'm confused because while some times doing things this way can make stuff easier (such as link_to which needs only to take the DependentOne model and will automatically route correctly) yet other items such as form_for refuse to work properly (because it doesn't route properly and if I add the CoreModel to the form_for it complains about no such route core_model_core_model_dependent_one etc....
Perhaps I haven't been clear enough and so I'll ensure I update this as requests for clarifications come in.
...the majority of the system only deals with that core class...
In that case, I wouldn't bother namespacing them.
The reason I feel like I should do this is because often two component areas of the same large application may need a supporting component with similar if not identical names as other areas of the software. I feel like name spacing these dependent models (which only exist to support that core model) is the best way to go.
Bingo - if you have name conflicts, namespacing is a good way to fix it. But, do you have that problem yet?
Namespacing prevents name conflicts, but in Rails it also introduces some gotchas and headaches and (throughout the app) quite a bit more typing. So, to me, it isn't worth it unless you actually have a name conflict.
Consider a structure like this, with your core model and many that just help it.
#Core Models
Model
Supporter
Assister
Helper
Benefactor
For most of the life of your app you may never run into a problem. If you do finally hit one, you could just do this:
AltModel
AltModel::Supporter
OtherModel
OtherModel::Benefactor
Or if it's really simple just prefixing the class name would work:
AltModelSupporter
OtherModelBenefactor
For that matter, it's probably simpler to name your core models in this way than it would be to "properly" namespace them:
CoreModel
CoreSupporter
CoreAssister
So, there are many ways to accomplish what you need, none of which suggest you should bother namespacing the core functionality of your app when you don't actually have a namespace conflict. Given the headaches you've already run into I think you'll be happier leaving the core models of your app in the top-level namespace and only nesting alternate models that actually have a conflict down the road.

in a Rails apps, how to organize Cucumber .feature files?

when i got to this project there were cucumber tests in "features/enhanced", which ran with javascript and a few in "features/plain" which did not require js. with the later development of per-scenario #javascript, this doesn't make sense. and as the number of features files we have grows and grows, it'd be awesome if this stayed tidy.
so, in best practice land:
1) how long should .feature files be? i try to keep each narrow and specific with 1 or 2 "Scenarios".
2) what folder/file structure should one keep them in?
2a) how might one group similar features?
1) Once you've done them for a few months you'll soon find what works best for you. My advice is you should make them small ish. We have often split our earlier features down into smaller chunks, but have never ended up combining them. It's handy for making use of backgrounds etc...
2) We had a big problem with this and spent ages doing it one way then another. In the end we gunned to group them by the services that our company provides. e.g. payments, customer registration, stock management
Inconveniently, features don't always conform to a hierarchical tree view of the world, so make liberal use of tagging and your primary grouping of features is less important.
Have you tried yard? There's an example here We've just built it into our CI, it lets you pull together sets of scenarios based on tags, you can do unions, intersections etc... well worth it :)
I would keep the JavaScript and non-JavaScript versions of a scenario together, since they should be very similar.
Anything more than 8 scenarios in a feature file is probably too much.
A useful approach is to have a folder to represent the high-levels features (sometimes call epics or themes), and separate feature files within those folders for the different aspects of the behaviour.
For example, you may have a feature "Employee Directory" which would have separate feature files contains scenarios for a photograph, office location, job title, etc.
Depending on the size and complexity of your app, you could group those folders into other folders.
(Note that none of the above is specific to Rails apps).

Shared models between two Rails apps - what is the ideal solution for Workflow?

I am currently working on a Rails 3 project that is divided up into four parts:
The public facing website
The administration website/backend
The models
The API for third party data access
As the models are shared between the three key components I want to keep them away from being in one main project, however each part needs access to the models, but I don't want to repeat the code and have different versions everywhere.
Currently I have the model code in a gem, and in each project's Gemfile I am referencing them with the following line:
gem "my_models", :path => "../my_models/"
However when I deploy to our test servers for my co-workers to evaluate the system on I need to pull the models from an external repository, so I swap out the above line with the following:
gem "my_models", :git => "git#private.repository.com:username/my_models.git"
This in its self works well, but its quite clunky in terms of 'versions' (i.e. I need to bump the version every time I wish to deploy the changes to the test servers), switch the line over to use git instead of local, and make sure that I'm pushing the files properly.
Previously I was using a shared git submodule, but this was just as awkward.
I would rather not build everything into one mega-project, as these tend to become monstrous and difficult to maintain, and I would also like to separate concerns if possible, so any changes I make to the administration site doesn't have much of a chance to impact the other components - obviously the models have the potential to cause issues, but that is a risk I have considered and understand.
What would people out there suggest when it comes to something like this? Or, am I going about it completely the wrong way?
Some additional background:
This app is a rewrite of an existing website which followed the model of 'lump everything into the one project' - unfortunately there are two issues here:
The app was badly developed - I inherited this project and when I first picked it up the load times were ~2 minutes per page with a single user - this has since been reduced but still has issues throughout
We are currently at our capacity limit of the current site and we anticipate that we will need to take on more load in the next 6 months - however scaling out with an 'all in one' app means we'll be wasting resources on scaling out the back end of the site which doesn't need it.
Essentially there are two things I want to separate - the Front end (being the public website and the API) and the back end - everything I know about software development tells me that combining all this together is not an ideal solution (and past history shows me that splitting these two is a good move in terms of ensuring front end performance).
Perhaps I need to look at this from another angle - keep the models in each project, and instead of sharing them between projects have a cut-down subset of functionality for each functional area (i.e. the backend needs to know who created a post, but the front end doesn't really care about that, so omit that logic when reading in the model).
drop the models project(put models into one of other parts, i'd suggest whatever you consider "more important"), put all projects into single repository(separate project folders) and make symlinks to models/libs/apis/whatever
your code is highly coupled together and you often need to make changes to few projects at once(like updating models and updating APIs that use them, etc)
one nice thing about single-repo-symlink setup is that your commits will be less fragmented and will usually represent full feature implementation - easier to track bugs, read history and maintain codebase
also when you deploy you don't need to read from many repositories - one less point of failure right there
release process is also simpler with such model as branch will now hold the scope of all projects
there are some drawbacks like symlinks dont work that well on windows and whatnot but for me it works perfectly
You can create a mountable engine that contains the shared models and create a gem out of it. This will handle the name spacing issues elegantly. Other nice aspect here is you get to share your assets also.
Watch this railscast for more details.
You'll still have to manage the 'versions' by pushing changes that need to be tested to a remote repo, but you can use the new local config of Bundler 1.2
http://gembundler.com/man/bundle-config.1.html#LOCAL-GIT-REPOS
This way it will pick up your local commits and you won't have to keep change your Gemfile upon deployment.
I know that this is not an solution for your particular problem. But I really suggest you to merge all projects into one. It is very usual to have all this parts in one application and there is no overhead. I think there is no not-awkward solution for this problem.
Take look at Git subtree.
This may work for you..
http://igor-alexandrov.github.io/blog/2013/03/28/using-git-subtree-to-share-code-between-rails-applications/
OR
You can write Rake task..
Example:-
namespace :sync do
desc 'Copy common models and tests from Master'
task :copy do
source_path = '/home/project/src-path'
dest_path = '/home/project/dest-path'
# Copy all models & tests
%x{cp #{source_path}/app/models/*.rb #{dest_path}/app/models/}
%x{cp #{source_path}/spec/models/*_spec.rb #{dest_path}/spec/models/}
# Database YML
%x{cp #{source_path}/config/database.yml #{dest_path}/config/database.yml}
end
See the below link.
http://hiltmon.com/blog/2013/10/14/rails-tricks-sharing-the-model/
Does your project have enough code coverage? If it does, I would try to separate the logic where it makes sense, and if a model is used in different projects, just pick one that fits best and write an API on top of that.
Then you could use that API to access those models (preferably using something like ActiveModel) on the other project. You would still have a simple CRUD, but all the core model logic would be handled externally.
Be sure to think well before splitting them up, though. You want to keep your domain tight on each app you create out of the Behemoth you want to torn apart.
Regarding engines:
I have used Engines for the same issue and it does help, but I also had to change my Gemfile to either point to a local path when developing, pushing the gem, then pulling it on the current project, which is the behavior you're not fond of.

Resources