Skip to content

Instantly share code, notes, and snippets.

@gabrielecanepa
Last active January 31, 2024 13:34
Show Gist options
  • Save gabrielecanepa/ca3c86c9254df5659877eec420ef771e to your computer and use it in GitHub Desktop.
Save gabrielecanepa/ca3c86c9254df5659877eec420ef771e to your computer and use it in GitHub Desktop.
Rails cheatsheet to implement common features 🛤️

Rails Cheatsheet

Authentication & Devise

See the Devise repository for more information.

  1. Add gem "devise" to the Gemfile and run:

    bundle install
    rails generate devise:install

    Then follow the instructions displayed in the terminal.

  2. Generate a devise model with rails generate devise User.

  3. Protect every route by default:

    # app/controllers/application_controller.rb
    
    class ApplicationController < ActionController::Base
      before_action :authenticate_user!
    end
  4. Skip the login for some pages:

    # app/controllers/pages_controller.rb
    
    class PagesController < ApplicationController
      skip_before_action :authenticate_user!, only: :home
    
      def home
      end
    end
  5. When adding new attributes to a devise model, specify them in the ApplicationController:

    # app/controllers/application_controller.rb
    
    class ApplicationController < ActionController::Base
      # [...]
      before_action :configure_permitted_parameters, if: :devise_controller?
    
      def configure_permitted_parameters
        # For additional fields in app/views/devise/registrations/new.html.erb
        devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name])
    
        # For additional in app/views/devise/registrations/edit.html.erb
        devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name])
      end
    end
  6. Optionally customize devise routes.

JavaScript

See the JavaScript in Rails guide for more information.

Stimulus

Generate Stimulus controllers with:

rails generate stimulus CONTROLLER_NAME

External libraries

importmap pin $NAME_OF_THE_LIBRARY

For example, to use flatpickr.js:

  1. Install the library and import the stylesheet in your main layout:

    importmap pin flatpickr
    <!-- app/views/layouts/application.html.erb -->
    
    <!-- ... -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  2. Create a specific datepicker controller:

    rails generate stimulus datepicker
    // app/javascript/controllers/datepicker_controller.js
    
    import { Controller } from '@hotwired/stimulus'
    import flatpickr from 'flatpickr';
    
    export default class extends Controller {
      connect() {
        flatpickr(this.element)
      }
    }
  3. Add the controller to the view:

    <%= f.input :opening_date,
        as: :string,
        input_html: { 
          data: { 
            controller: "datepicker" 
          } 
        }
    %>

AJAX

  1. Set up the controller to return a JSON response using respond_to:

    # app/controllers/monuments_controller.rb
    
    # [...]
    def create
      @monument = Monument.new(monument_params)
    
      respond_to do |format|
        if @monument.save
          format.html { redirect_to monument_path(@monument) }
          format.json # looks for a create.json view
        else
          format.html { render "monuments/new", status: :unprocessable_entity }
          format.json # looks for a create.json view
        end
      end
    end
  2. Make sure that the jbuilder gem is installed and create a create.json.jbuilder view:

    # app/views/monuments/create.json.jbuilder
    
    if @monument.persisted?
      json.form render(partial: "monuments/form", formats: :html, locals: { monument: Monument.new })
      json.inserted_item render(partial: "monuments/monument", formats: :html, locals: { monument: @monument })
    else
      json.form render(partial: "monuments/form", formats: :html, locals: { monument: @monument })
    end
  3. Generate a new Stimulus controller to handle the request:

    rails generate stimulus insert_in_list
    // app/javascript/controllers/insert_in_list_controller.js
    
    import { Controller } from '@hotwired/stimulus'
    
    export default class extends Controller {
      static targets = ['items', 'form']
    
      send(event) {
        event.preventDefault();
    
        fetch(this.formTarget.action, {
          method: 'POST',
          headers: { Accept: 'application/json' },
          body: new FormData(this.formTarget)
        })
          .then(response => response.json())
          .then((data) => {
            if (data.inserted_item) {
              this.itemsTarget.insertAdjacentHTML('beforeend', data.inserted_item)
            }
            this.formTarget.outerHTML = data.form
          })
      }
    }
  4. Connect the controller to the DOM:

    <!-- app/views/monument/index.html.erb -->
    
    <div class="container">
      <div class="row">
        <div class="col" data-controller="insert-in-list">
          <div id="monuments" data-insert-in-list-target="items">
            <!-- ... -->
          </div>
        </div>
      </div>
    </div>
    <!-- app/views/monument/_form.html.erb -->
    
    <%= simple_form_for monument,
        data: {
          insert_in_list_target: "form",
          action: "submit->insert-in-list#send"
        } do |f| %>
      <!-- ... -->
    <% end %>

Geocoding

  1. Install and configure the geocoder gem:

    # Gemfile
    
    # ...
    gem "geocoder"
    bundle install
    rails generate geocoder:config
    # config/initializers/geocoder.rb
    Geocoder.configure(
      # [...]
      units: :km, # Defaults to miles (:mi)
    )
  2. Add the coordinates columns and update the model:

    rails g migration AddCoordinatesToFlats latitude:float longitude:float
    rails db:migrate
    # app/models/flat.rb
    
    class Flat < ApplicationRecord
      geocoded_by :address
      after_validation :geocode, if: :will_save_change_to_address?
    end
  3. Create a geocoded instance and search for nearby instances:

    # rails console
    Flat.create(address: "16 Villa Gaudelet, Paris", name: "Le Wagon HQ")
    # => #<Flat:0x007fad2e720898
    # id: 1,
    # name: "Le Wagon HQ",
    # address: "16 Villa Gaudelet, Paris",
    # latitude: 48.8649574,
    # longitude: 2.3800617>
    
    Flat.near("Tour Eiffel", 10)   # flats within 10 km of Tour Eiffel
    Flat.near([40.71, 100.23], 20) # flats within 20 km of a point
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment