All Projects → NullVoxPopuli → Drawers

NullVoxPopuli / Drawers

Licence: mit
Group related classes together. No more silos. A solution to rails dystopia.

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Drawers

drawer-with-bottom-navigation-architecture
Sample android kotlin project with both drawer and bottom navigation together
Stars: ✭ 42 (-72%)
Mutual labels:  drawer, architecture
Jsonapi Utils
Build JSON API-compliant APIs on Rails with no (or less) learning curve.
Stars: ✭ 191 (+27.33%)
Mutual labels:  rails, resource
Stimulus reflex
Build reactive applications with the Rails tooling you already know and love.
Stars: ✭ 1,928 (+1185.33%)
Mutual labels:  rails
Rack Policy
Rack middleware for the EU ePrivacy Directive compliance in Ruby Web Apps
Stars: ✭ 149 (-0.67%)
Mutual labels:  rails
Font awesome5 rails
font_awesome_5_rails is font awesome 5 gem bundled for rails asset pipeline
Stars: ✭ 148 (-1.33%)
Mutual labels:  rails
Api Guidelines
adidas group API design guidelines
Stars: ✭ 147 (-2%)
Mutual labels:  architecture
Blockchain rd checklist
blockchain resources list
Stars: ✭ 148 (-1.33%)
Mutual labels:  resource
Materialdrawer
The flexible, easy to use, all in one drawer library for your Android project. Now brand new with material 2 design.
Stars: ✭ 11,498 (+7565.33%)
Mutual labels:  drawer
Coverband
Ruby production code coverage collection and reporting (line of code usage)
Stars: ✭ 1,937 (+1191.33%)
Mutual labels:  rails
Provider architecture template
A production ready flutter application template for the provider architecture.
Stars: ✭ 148 (-1.33%)
Mutual labels:  architecture
Trado
Trado is a lightweight, easy to use ecommerce platform; designed to allow developers to quickly deploy a premium ecommerce store for their business
Stars: ✭ 149 (-0.67%)
Mutual labels:  rails
Pytorch Vae
A Collection of Variational Autoencoders (VAE) in PyTorch.
Stars: ✭ 2,704 (+1702.67%)
Mutual labels:  architecture
Kingly
Zero-cost state-machine library for robust, testable and portable user interfaces (most machines compile ~1-2KB)
Stars: ✭ 147 (-2%)
Mutual labels:  architecture
Innocenceengine
Cross-platform modern game engine.
Stars: ✭ 149 (-0.67%)
Mutual labels:  architecture
Suas Ios
Unidirectional data flow architecture implementation for iOS, macOS, tvOS and watchOS
Stars: ✭ 147 (-2%)
Mutual labels:  architecture
Jstarcraft Core
目标是提供一个通用的Java核心编程框架,作为搭建其它框架或者项目的基础. 让相关领域的研发人员能够专注高层设计而不用关注底层实现. 涵盖了缓存,存储,编解码,资源,脚本,监控,通讯,事件,事务9个方面.
Stars: ✭ 150 (+0%)
Mutual labels:  resource
Doorkeeper Provider App
An example OAuth 2 provider application using the Doorkeeper gem, Rails and Devise
Stars: ✭ 146 (-2.67%)
Mutual labels:  rails
Recaptcha
ReCaptcha helpers for ruby apps
Stars: ✭ 1,819 (+1112.67%)
Mutual labels:  rails
Graphql Query Resolver
Minimize N+1 queries generated by GraphQL and ActiveRecord
Stars: ✭ 148 (-1.33%)
Mutual labels:  rails
Rpush
The push notification service for Ruby.
Stars: ✭ 1,886 (+1157.33%)
Mutual labels:  rails

Drawers

Group related classes together. No more silos.

Gem Version Build Status Code Climate Test Coverage Dependency Status

What is this about?

With large rails application, the default architecture can result in a resource's related files being very spread out through the overall project structure. For example, lets say you have 50 controllers, serializers, policies, and operations. That's four different top level folders that spread out all the related objects. It makes sense do it this way, as it makes rails' autoloading programmatically easy.

This gem provides a way to re-structure your app so that like-objects are grouped together.

All this gem does is add some new autoloading / path resolution logic. This gem does not provide any service/operation/policy/etc functionality.

All of this is optional, and can be slowly migrated to over time. Adding this gem does not force you to change your app.

The new structure

app/
├── channels/
├── models/
   ├── data/
      ├── post.rb
      └── comment.rb
   └── graph_data.rb
├── jobs/
├── mailers/
   └── notification_mailer.rb
└── resources/
    ├── posts/
       ├── forms/
          └── new_post_form.rb
       ├── controller.rb  # or posts_controller.rb
       ├── operations.rb  # or post_operations.rb
       ├── policy.rb      # or post_policy.rb
       └── serializer.rb  # or post_serializer.rb
    └── comments/
        ├── controller.rb
        ├── serializer.rb
        └── views/
            ├── index.html.erb
            └── create.html.erb

Does this new structure mean you have to change the class names of all your classes? Nope. In the above example file structure, app/resources/posts/controller.rb still defines class PostsController < ApplicationController

Checkout the sample rails app in the tests directory.

The Convention

Say, for example, you have any class/module defined as:

module Api                    # {namespace
  module V3                   #  namespace}
    module UserServices       # {resource_name}{resource_type}
      module Authentication   # {class_path
        class OAuth2          #  class_path/file_name}
        end
      end
    end
  end
 end

As long as some part of the fully qualified class name (in this example: Api::V3::UserServices::Authentication::OAuth2) contains any of the defined keywords, the file will be found at app/resources/api/v3/users/services/authentication/oauth2.rb.

The pattern for this is: app/resources/:namespace/:resource_name/:resource_type/:class_path where:

  • :namespace is the namespace/parents of the UserService
  • :resource_type is a suffix that may be inferred by checking of the inclusion of the defined keywords (linked above)
  • :resource_name is the same module/class as what the resource_type is derived from, sans the resource_type
  • :class_path is the remaining namespaces and eventually the class that the target file defines.

So... what if you have a set of classes that don't fit the pattern exactly? You can leave those files where they are currently, or move them to app/resources, if it makes sense to do so. Feel free to open an issue / PR if you feel the list of resource types needs updating.

Usage

gem 'drawers'

Including the gem in your gemfile enables the new structure.

A note for ActiveModelSerializers

ActiveModelSerializers, by default, does not consider your controller's namespace when searching for searializers.

To address that problem, you'll need to add this to the serializer lookup chain

# config/initializers/active_model_serializers.rb
ActiveModelSerializers.config.serializer_lookup_chain.unshift(
  lambda do |resource_class, _, namespace|
    "#{namespace.name}::#{resource_class.name}Serializer" if namespace
  end
)

Note: as of 2016-11-04, only this branch of AMS supports a configurable lookup chain

Note: as of 2016-11-16, the master (>= v0.10.3) branch of AMS supports configurable lookup chain.

Migrating

Each part of your app can be migrated gradually (either manually or automatically).

In order to automatically migrate resources, just run:

rake rmu:migrate_resource[Post]

This will move all unnamespaced classes that contain any of the supported resource suffixes to the app/resources/posts directory.

Configuration

# (Rails.root)/config/initializers/drawers.rb
Drawers.directory = 'pods'

Sets the folder for the new structure to be in the app/pods directory if you want the new structure separate from the main app files.

Co-Location of Tests / Specs

There are some mixed feelings about co-location of specs, so (by default), this monkey patch is not included.

# config/initializers/gems/rails.rb
module Rails
  class Engine
    # https://github.com/rails/rails/blob/5-1-stable/railties/lib/rails/engine.rb#L472-L479
    # https://github.com/rails/rails/blob/4-2-stable/railties/lib/rails/engine.rb#L468
    def eager_load!
      config.eager_load_paths.each do |load_path|
        matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/
        # They key is the !(spec) added to the glob pattern.
        # You may need to modify this if your tests don't end with spec
        Dir.glob("#{load_path}/**/*!(spec).rb").sort.each do |file|
          require_dependency file.sub(matcher, '\1')
        end
      end
    end
  end
end

Your test suite command would then need to change to include the app directory.

rspec app/ spec/

And you'll still want to use the spec folder for spec_helper.rb, factories, and other support things.

Contributing

Feel free to open an issue, or fork and make a pull request.

All discussion is welcome :-)


The gem name 'Drawers' was provided by @bartboy011. Thanks @bartboy011!

The previous name of this gem was Rails Module Unification -- which, while a homage to its inspiration, Ember's Module Unification app architecture, it's quite a mouthful, and doesn't exactly make for a good gem name.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].