How to build a Rails app
in 48 hours without using the RailsWay™
Setup
Outcome
Share your jewels with your community
This talk is the exact opposite of the RailsWay™.
If you really like the RailsWay™ and have heart disease, this talk might be dangerous for you.
Model
Service
Query
Validation
Controller
Context
Presenter
Template
Helper
module Gempackages
class StatsQuery < BaseQuery
@model = Gempackage
module Scopes
def maximum_usage(threshold)
group(:id)
.having('count(*) <= ?', threshold)
.select('count(*) as usage_count, gempackages.*')
end
def maximum_stargazers(threshold)
where('github_stars <= ?', threshold)
end
def minimum_stargazers(threshold)
where('github_stars >= ?', threshold)
end
def sort_by_top_stargazers
order(github_stars: :desc)
end
end
end
end
Gempackages::StatsQuery
.all(survey.gempackages)
.minimum_stargazers(Settings.gempackages.outsiders_stargazers_min_threshold)
.maximum_stargazers(Settings.gempackages.outsiders_stargazers_max_threshold)
.merge(not_much_used_gems)
.sort_by_top_stargazers
.limit(Settings.gempackages.outsiders_max_threshold)
class GemfileForm < Reform::Form
property :owner_name
property :document, virtual: true
validates :owner_name, presence: true
validates :document, presence: true
validates :document, file_size: { less_than: 2.megabytes },
file_content_type: { allow: 'application/octet-stream' }
validate :document_is_gemfile
private
def document_is_gemfile
return if document.nil?
Bundler::Definition.build(document.tempfile, nil, nil)
rescue
errors.add(:document, 'must be a Gemfile')
end
end
gemfile = Gemfile.new
form = GemfileForm.new(gemfile)
fail Errors::ValidationError.new({ form: form }) unless form.validate(params)
form.sync
module Gemfiles
class CreateService < BaseService
# `attr_reader`s and `initialize`...
def call
fail Gemfiles::ClosedSurveyError.new(survey) if survey.closed?
fail Errors::ValidationError.new({ form: form }) unless form.validate(params)
form.sync
gemfile.assign_attributes attributes
gemfile.save!
perform_job(Gemfiles::ImportJob, gemfile.id)
gemfile
end
private
# helper methods
end
end
def foo
gemfile_creator = Gemfiles::CreateService.new(GemfileForm, survey.id, params[:gemfile])
gemfile = gemfile_creator.call
rescue Errors::ValidationError => exception
# do some stuff
end
class SurveyPresenter
private
attr_reader :survey
public
def initialize(survey)
@survey = survey
end
def period
opening_on = I18n.l(survey.created_at.to_date, format: :long)
closing_on = I18n.l(survey.closing_on, format: :long)
"#{opening_on} - #{closing_on}"
end
def when_is_open(&block)
block.call unless survey.closed?
end
end
survey = ::Surveys::FindByCodeService.new(group.id, params[:id]).call
@survey_presenter = SurveyPresenter.new(survey)
module Surveys
class ShowContext
private
attr_reader :survey, :stats
public
delegate :logo_url, to: :group, prefix: true
delegate :when_is_open, to: :survey_presenter
def initialize(survey, stats)
@survey = survey
@stats = stats
end
private
def survey_presenter
@survey_presenter ||= SurveyPresenter.new(survey)
end
end
end
(should be named views!)
def show
survey = ::Surveys::FindByCodeService.new(group.id, params[:id]).call
stats = ::Surveys::GenerateStatsService.new(survey.id).call
@context = ::Surveys::ShowContext.new(survey, stats)
end
module Groups
class SurveysController < Groups::BaseController
before_action :authorize!, only: [:new, :create, :edit, :update]
def create
survey = ::Surveys::CreateService.new(SurveyForm, group.id, params[:survey]).call
flash[:notice] = "Survey #{survey.name} has been succesfully created"
redirect_to group_path(group, token: params[:token])
rescue Errors::ValidationError => exception
@context = ::Surveys::ActionContext.new(group, exception.context[:form])
flash.now[:alert] = 'We were not able to create your survey'
render :new
end
def show
stats = ::Surveys::GenerateStatsService.new(survey.id).call
@context = ::Surveys::ShowContext.new(survey, stats)
end
# ... other actions ...
private
def survey
@survey ||= ::Surveys::FindByCodeService.new(group.id, params[:id]).call
end
end
end
module MaterializeHelper
Flash = Struct.new(:title, :classes)
FLASH_TYPES = {
"alert" => MaterializeHelper::Flash.new("Oooops!", "error"),
"notice" => MaterializeHelper::Flash.new("Well done!", "success")
}
def flash_type_to_class_names(type)
FLASH_TYPES[type].classes
end
def flash_type_to_title(type)
FLASH_TYPES[type].title
end
end
Website:
Source code:
http://gemsavvy.tips
http://github.com/ruby-nord/gemsavvy
The project is Open Source,
don't hesitate to come by and contribute.