Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
От Rails-way к модульной архитектуре
1. From rails-way to
modular architecture
Ivan Nemytchenko,
independent consultant
DevConf 2014
@inem, @inemation
2. Icon made by <a href="http://www.freepik.com" alt="Freepik.com">Freepik</a>
from <a href="http://www.flaticon.com/free-icon/graduate-cap_46045">flaticon.com</a>
Icon made by Icons8 from <a href="http://www.flaticon.com">flaticon.com</a>
16. Модели
class ImageSettings < ActiveRecord::Base
end
class Profile < ActiveRecord::Base
self.table_name = 'profile'
belongs_to :image, foreign_key: :picture_id
end
17. Модели
class Image < ActiveRecord::Base
self.table_name = 'image'
has_and_belongs_to_many :image_variants,
join_table: "image_image",
class_name: "Image",
association_foreign_key: :image_images_id
belongs_to :settings,
foreign_key: :settings_id,
class_name: 'ImageSettings'
belongs_to :asset
end
18. RABL - github.com/nesquena/
rabl
collection @object
attribute :id, :deleted, :username, :age
node :gender do |object|
object.gender.to_s
end
node :thumbnail_image_url do |obj|
obj.thumbnail_image.asset.url
end
node :standard_image_url do |obj|
obj.standard_image.asset.url
end
20. def redeem
unless bonuscode = Bonuscode.find_by_hash(params[:code])
render json: {error: 'Bonuscode not found'}, status: 404 and return
end
if bonuscode.used?
render json: {error: 'Bonuscode is already used'}, status: 404 and return
end
unless recipient = User.find_by_id(params[:receptor_id])
render json: {error: 'Recipient not found'}, status: 404 and return
end
unless ['regular', 'paying'].include?(recipient.type)
render json: {error: 'Incorrect user type'}, status: 404 and return
end
ActiveRecord::Base.transaction do
amount = bonuscode.mark_as_used!(params[:receptor_id])
recipient.increase_balance!(amount)
if recipient.save && bonuscode.save
render json: {balance: recipient.balance}, status: 200 and return
else
render json: {error: 'Error during transaction'}, status: 500 and return
end
end
end
21.
22. def redeem
begin
recipient_balance = ??????????
rescue BonuscodeNotFound, BonuscodeIsAlreadyUsed, RecipientNotFound => ex
render json: {error: ex.message}, status: 404 and return
rescue IncorrectRecipientType => ex
render json: {error: ex.message}, status: 403 and return
rescue TransactionError => ex
render json: {error: ex.message}, status: 500 and return
end
render json: {balance: recipient_balance}
end
31. Form objects (Inputs)
4 Plain old ruby objects*
class BonuscodeRedeemInput < Input
attribute :hash_code, String
attribute :receptor_id, Integer
validates_presence_of :hash_code, :receptor_id
validates_numericality_of :receptor_id
end
32. Form objects (Inputs)
class Input
include Virtus.model
include ActiveModel::Validations
class ValidationError < StandardError; end
def validate!
raise ValidationError.new, errors unless valid?
end
end
35. class SenderApp < Sinatra::Base
get '/sms/create/:message/:number' do
input = MessageInput.new(params)
sender = TwilioMessageSender.new('xxxxxx', 'xxxxxx', '+15005550006')
use_case = SendSms.new(input, sender)
begin
use_case.run!
rescue ValidationError => ex
status 403 and return ex.message
rescue SendingError => ex
status 500 and return ex.message
end
status 201
end
end
36. Sinatra
4 встраивается в рельсовые роуты или
запускается в связке с другими rack-
приложениями
4 рельсовые роуты оказались ненужной
абстракцией
4 отчего бы не применить такой подход для
всего приложения?!
55. class ProfilePresenter
def initialize(p, viewer)
...
def wrap!
hash = { id: p.id, deleted: p.deleted,
username: p.username, is_online: p.is_online }
hash[:user_id] = p.user_id if viewer.admin?
hash[:image] = p.image.to_hash if add_image?
hash
end
def self.wrap!(profiles, viewer)
profiles.map do |profile|
new(profile, viewer).wrap!
end
end
...
end
56. Presenters
post '/profile' do
begin
use_case = CreateProfile.new(current_user)
profile = use_case.run!(params)
rescue Input::ValidationError => ex
halt 403
end
wrapped_profiles = ProfilePresenter.wrap!([profile], current_user)
json(data: wrapped_profiles)
end