Skip to content

Instantly share code, notes, and snippets.

@slavone
Last active November 13, 2015 09:46
Show Gist options
  • Save slavone/c199b9ce22bafb3dc855 to your computer and use it in GitHub Desktop.
Save slavone/c199b9ce22bafb3dc855 to your computer and use it in GitHub Desktop.
user_privileges_problem

Здесь особых сложностей не возникло. С фильтрацией действий на контроллерах рельсы сами по себе справляются, по-моему, вполне неплохо, главное учесть все варианты. В этом сильно помогает написание функциональных тестов.

Контроллер для товаров приведен ниже. Фильтры before_action не пропускают юзеров туда, куда им ходить не следует. При дальнейшем расширении, даже не смотря на растущие условия типа current_user.is_some_type_1? || current_user.is_some_type2? || current_user.is_some_type3?, мне кажется такое решение вполне устойчивым и расширяемым. Можно ли это сделать как-то еще оптимальнее?

С views все хуже, в них логика очень быстро накапливается и становится плохо отслеживаемой, ниже приведена пара примеров. Я гуглил по этому поводу, советует использовать декораторы. Какой наиболее правильный способ реализации этого паттерна в рельсах? Гем Draper вроде бы является самым рекомендуемым решением.

Еще вопрос по логике в views c формами. Админ и владелец магазинов оба могут редактировать товары, только редактировать они могут разные атрибуты. Решил я это через if elsif внутри партиала (файл _product_form.html.haml). Адекватное ли это решение, или можно лучше? Думаю, что как минимум нужно еще больше поделить на партиалы.

%header
%nav{class: ['navbar', 'navbar-default']}
.container-fluid
.navbar-header
%button{ type: 'button', class: %w(navbar-toggle collapsed),
data: { toggle: 'collapse', target: '#navbar' },
aria: { expanded: 'false', contols: 'navbar' } }
%span{ class: 'sr-only'}
Toggle navigation
%span{ class: 'icon-bar' }
%span{ class: 'icon-bar' }
%span{ class: 'icon-bar' }
%a{ class: 'navbar-brand', href: root_path }
Text exercise. Part 4
#navbar.collapse.navbar-collapse
%ul{ class: %w(nav navbar-nav navbar-right) }
%li
= link_to "Products", products_path
-if logged_in?
- if current_user.is_admin?
%li
= link_to "Users", user_logins_path
%li{ class: 'dropdown' }
%a{ class: 'dropdown-toggle', role: 'button',
data: { toggle: 'dropdown' },
aria: { hashpopup: 'true', expanded: 'false' } }
= current_user.email
%span{ class: 'caret' }
%ul{ class: 'dropdown-menu' }
%li
= link_to 'Edit profile', edit_polymorphic_path([:users, current_user.user])
%li
= link_to 'Log out', log_out_path, method: :delete
-else
%li{ class: 'dropdown' }
%a{ class: 'dropdown-toggle', role: 'button',
data: { toggle: 'dropdown' },
aria: { hashpopup: 'true', expanded: 'false' } }
Sign up
%span{ class: 'caret' }
%ul{ class: 'dropdown-menu' }
%li
= link_to 'Sign up as admin', new_users_admin_path
%li
= link_to 'Sign up as shop owner', new_users_shop_owner_path
%li
= link_to 'Sign up as guest', new_users_guest_path
%li
= link_to 'Log in', log_in_path
= form_for @product, html: { multipart: true } do |f|
- if @product.errors.any?
%ul
- @product.errors.full_messages.each do |msg|
%li
= msg
- if current_user.is_shop_owner?
.form-group
= f.label :name
= f.text_field :name, autofocus: true
.form-group
= f.label :image
= f.file_field :image
.form-group
= f.label :description
= f.text_area :description
.form-group
= f.label :shop_name
= f.text_field :shop_name, disabled: true
.form-group
= f.label :associate?, class: 'checkbox inline' do
- if @product.shop_name != ''
= check_box_tag :associate?, '1', true
- else
= check_box_tag :associate?, '1', false
%span
Associate with the shop?
- elsif current_user.is_admin?
.form-group
= f.label :name
= f.text_field :name, disabled: true
.form-group
= f.label :description
= f.text_area :description, disabled: true
.form-group
-if @product.shop_name != ''
= f.label "Shop: #{@product.shop_name}"
- else
= "Not associated with any shop."
.form-group
= f.label :status, class: 'checkbox inline' do
- if @product.status == 'pro'
- @product.status = '1'
- else
- @product.status = '0'
= f.check_box :status
%span
Pro?
.actions
- if @product.id.nil?
= f.submit "Create product", class: %w(btn btn-default)
- else
= f.submit "Change product", class: %w(btn btn-default)
= link_to "Back", :back
.container
.text-center
%h1 All available products
- if @products.any?
.row
- @products.each do |p|
.col-sm-6.col-md-4
.thumbnail
= image_tag p.image_url
.caption
%h3
= link_to "#{p.name}", product_path(p)
%h4
- if p.shop_name != ''
= "Shop: #{p.shop_name}" if logged_in? && !current_user.is_guest?
%p
= p.description
- if logged_in? && current_user.is_guest? && p.shop_name != "" && p.status != 'pro'
= link_to "Purchase", new_purchase_path
- else
%p Seems like no products have been added yet.
= link_to "Add new product", new_product_path if logged_in? && current_user.is_shop_owner?
class ProductsController < ApplicationController
before_action :can_add_products?, only: [:new, :create, :destroy]
before_action :can_edit_products?, only: [:edit, :update]
def index
if logged_in?
case current_user.user_type
when 'Admin'
@products = Product.all
when 'ShopOwner'
@products = Product.all
when 'Guest'
@products = Product.all
end
else
@products = Product.where.not(status: 'pro')
end
end
def show
@product = Product.find(params[:id])
if !logged_in? && @product.status == 'pro'
flash[:danger] = 'Access denied.'
redirect_to products_path
return
end
end
def new
@product = Product.new
end
def create
@product = Product.new(product_params)
if @product.save
flash[:info] = "New product \"#{@product.name}\" has been created."
redirect_to products_path
else
render 'new'
end
end
def edit
@product = Product.find(params[:id])
end
def update
@product = Product.find(params[:id])
if @product.update_attributes(product_params_on_edit)
flash[:info] = "Product \"#{@product.name}\" information has been updated."
redirect_to products_path
else
render 'edit'
end
end
def destroy
@product = Product.find(params[:id])
@product.destroy
flash[:info] = "Product \"#{@product.name}\" has been deleted."
redirect_to products_path
end
private
def can_add_products?
unless logged_in? && current_user.is_shop_owner?
flash[:danger] = 'Access denied.'
redirect_to products_path
end
end
def can_edit_products?
unless logged_in? && (current_user.is_shop_owner? || current_user.is_admin?)
flash[:danger] = 'Access denied.'
redirect_to products_path
end
end
def product_params
if params[:associate?]
p = params.require(:product).permit(:name, :description, :image)
p[:shop_name] = current_user.user.shop_name
return p
else
p = params.require(:product).permit(:name, :description, :image)
p[:shop_name] = ''
p
end
end
def product_params_on_edit
if current_user.is_admin?
p = params.require(:product).permit(:status)
p['status'] == '1' ? p['status'] = 'pro' : p['status'] = ''
p
elsif current_user.is_shop_owner?
product_params
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment