Страницы

Поиск по вопросам

Показаны сообщения с ярлыком ruby-on-rails. Показать все сообщения
Показаны сообщения с ярлыком ruby-on-rails. Показать все сообщения

понедельник, 13 апреля 2020 г.

Не работает gem 'bcrypt-ruby' в Rails 4.0.0

#gems #ruby #ruby_on_rails

                    
Добрый день.
У меня стоит Ruby 2 и Rails 4. Проблемы возникли с gem 'bcrypt-ruby'. При установке
gem 'bcrypt-ruby', '~> 3.0.0' устанавливается версия gem 3.0.1. Рестарт.
Появляется ошибка 
cannot load such file -- 2.0/bcrypt_ext
This error occurred while loading the following files:
   bcrypt
   bcrypt_ext
   2.0/bcrypt_ext

Удалил этот гем и поставил версию gem 'bcrypt-ruby', '~> 3.1.0'. Устанавливается
версия gem 3.1.2. Рестарт. Появляется другая ошибка:
    can't activate bcrypt-ruby (~> 3.0.0), already activated bcrypt-ruby-3.1.2-x86-mingw32.
Make sure all dependencies are added to Gemfile:
app/models/user.rb:4:in `'
app/models/user.rb:1:in `'
app/controllers/users_controller.rb:7:in `new'

В интернете довольно часто встречались эти проблемы, но везде совет один и тот же:
переустановить гем, и перезапустить сервер. Мне это не помогло. Проект делается на
Windows 7, по техническим причинам поставить Linux нет возможности. На rails 3.2.12
все работало прекрасно. А здесь нет. 
Спасибо за внимание.
Gemfile.lock
    GEM
  remote: http://rubygems.org/
  specs:
    actionmailer (4.0.0)
      actionpack (= 4.0.0)
      mail (~> 2.5.3)
    actionpack (4.0.0)
      activesupport (= 4.0.0)
      builder (~> 3.1.0)
      erubis (~> 2.7.0)
      rack (~> 1.5.2)
      rack-test (~> 0.6.2)
    activemodel (4.0.0)
      activesupport (= 4.0.0)
      builder (~> 3.1.0)
    activerecord (4.0.0)
      activemodel (= 4.0.0)
      activerecord-deprecated_finders (~> 1.0.2)
      activesupport (= 4.0.0)
      arel (~> 4.0.0)
    activerecord-deprecated_finders (1.0.3)
    activesupport (4.0.0)
      i18n (~> 0.6, >= 0.6.4)
      minitest (~> 4.2)
      multi_json (~> 1.3)
      thread_safe (~> 0.1)
      tzinfo (~> 0.3.37)
    arel (4.0.0)
    atomic (1.1.13)
    bcrypt-ruby (3.1.2-x86-mingw32)
    builder (3.1.4)
    coffee-rails (4.0.0)
      coffee-script (>= 2.2.0)
      railties (>= 4.0.0.beta, < 5.0)
    coffee-script (2.2.0)
      coffee-script-source
      execjs
    coffee-script-source (1.6.3)
    erubis (2.7.0)
    execjs (2.0.0)
    hike (1.2.3)
    i18n (0.6.5)
    jbuilder (1.5.1)
      activesupport (>= 3.0.0)
      multi_json (>= 1.2.0)
    jquery-rails (3.0.4)
      railties (>= 3.0, < 5.0)
      thor (>= 0.14, < 2.0)
    json (1.8.0)
    mail (2.5.4)
      mime-types (~> 1.16)
      treetop (~> 1.4.8)
    mime-types (1.24)
    minitest (4.7.5)
    multi_json (1.7.9)
    polyglot (0.3.3)
    protected_attributes (1.0.3)
      activemodel (>= 4.0.0, < 5.0)
    rack (1.5.2)
    rack-test (0.6.2)
      rack (>= 1.0)
    rails (4.0.0)
      actionmailer (= 4.0.0)
      actionpack (= 4.0.0)
      activerecord (= 4.0.0)
      activesupport (= 4.0.0)
      bundler (>= 1.3.0, < 2.0)
      railties (= 4.0.0)
      sprockets-rails (~> 2.0.0)
    railties (4.0.0)
      actionpack (= 4.0.0)
      activesupport (= 4.0.0)
      rake (>= 0.8.7)
      thor (>= 0.18.1, < 2.0)
    rake (10.1.0)
    rdoc (3.12.2)
      json (~> 1.4)
    sass (3.2.10)
    sass-rails (4.0.0)
      railties (>= 4.0.0.beta, < 5.0)
      sass (>= 3.1.10)
      sprockets-rails (~> 2.0.0)
    sdoc (0.3.20)
      json (>= 1.1.3)
      rdoc (~> 3.10)
    sprockets (2.10.0)
      hike (~> 1.2)
      multi_json (~> 1.0)
      rack (~> 1.0)
      tilt (~> 1.1, != 1.3.0)
    sprockets-rails (2.0.0)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      sprockets (~> 2.8)
    sqlite3 (1.3.8-x86-mingw32)
    thor (0.18.1)
    thread_safe (0.1.2)
      atomic
    tilt (1.4.1)
    treetop (1.4.15)
      polyglot
      polyglot (>= 0.3.1)
    turbolinks (1.3.0)
      coffee-rails
    tzinfo (0.3.37)
    uglifier (2.2.0)
      execjs (>= 0.3.0)
      multi_json (~> 1.0, >= 1.0.2)

PLATFORMS
  x86-mingw32

DEPENDENCIES
  bcrypt-ruby
  coffee-rails (~> 4.0.0)
  jbuilder (~> 1.2)
  jquery-rails
  protected_attributes
  rails (= 4.0.0)
  sass-rails (~> 4.0.0)
  sdoc
  sqlite3
  turbolinks
  uglifier (>= 1.3.0)

Gemfile
source 'http://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.0'

# Use sqlite3 as the database for Active Record
gem 'sqlite3'

# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'

# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'

# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'

group :doc do
  # bundle exec rake doc:rails generates the API under doc/api.
  gem 'sdoc', require: false
end

gem 'protected_attributes'

# Use ActiveModel has_secure_password
gem 'bcrypt-ruby'
    


Ответы

Ответ 1



Если нет возможности ставить и работать на линуксе - используйте VirtualBox + Vagrant. Сбережёте себе не один гигабайт нервных клеток (: ps: если gem list bcrypt-ruby выдаёт несколько гемсов - убейте младший.

Ответ 2



в Gemfile.lock замените bcrypt-ruby (3.1.2-x86-mingw32) на bcrypt-ruby (3.1.2) и все будет работать

Связь многие ко многим в Rails

#ruby #ruby_on_rails

                    
Хочу связать тэги с постами, есть три модели:

    class Post < ActiveRecord::Base
      has_many :tag_to_post
      has_many :tags, :through => :tag_to_post
    end

class Tag < ActiveRecord::Base
  has_many :tag_to_post
  has_many :posts, :through=> :tag_to_post
end

class TagToPost < ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end


В консоли ввожу post=Post.find(Id_существующего поста)
После чего ввожу post.tags и получаю ошибку: 


  Circular dependency detected while autoloading constant TagToPost.


До того как написал сюда, нашёл вот такую запись: Rails: Why “has_many …, :through
=> …” association results in “NameError: uninitialized constant …”, где задача по всей
видимости схожа с моей, после чего модели были приведены к текущему виду (до этого
была другая ошибка "nameerror uninitialized constant").
Подскажите, пожалуйста, как решить мою проблему.
    


Ответы

Ответ 1



У вас has_many :tag_to_post А должно быть has_many :tag_to_posts

суббота, 11 апреля 2020 г.

Ассоциации Rails - Автоматический выбор текущего пользователя как автора поста

#ruby #ruby_on_rails

                    
Доброго времени суток! Подскажите, пожалуйста, имеются две модели:
class User < ActiveRecord::Base
  has_many :hotels
end

и
class Hotel < ActiveRecord::Base
  belongs_to :user
end

Миграция:
class AddUserIdToHotels < ActiveRecord::Migration
  def change
    add_column :hotels, :user_id, :integer
  end
end

Форма создания нового поста про отель:
<%= simple_form_for(@hotel, :html => {:multipart => true}) do |f| %>
  <%= f.input  :title %>
  <%= f.input  :star_rating, collection: 1..5 %>
  <%= f.input  :room_description, as: :text %>
  <%= f.input  :price_for_room %>
  

Address

<%= f.select :hotels_country, priority: ["Ukraine", "Russia", "Europe"] %> <%= f.input :state %> <%= f.input :city %> <%= f.input :street %> <%= f.input :breakfast_included %> <%= f.input :photo, as: :file %> <%= f.association :user %> <%= f.button :submit, class: "btn btn-large btn-primary" %> <% end %> Вопрос: как реализовать, чтобы при создании поста про новый отель в таблице hotels в поле user_id был текущий пользователь? При выше приведенной реализации получается, что в строке <%= f.association :user %> есть выпадающий список всех пользователей из таблицы users, а необходим только текущий, чтобы каждый пост автоматически был привязан к пользователю, который его создал.


Ответы

Ответ 1



например в контроллере перед сохранением отеля: @hotel.user_id = current_user.id можно и через hidden_field в форме, только этот вариант не секурен

Ответ 2



Можно проще? @hotel = current_user.hotel.create(params)

четверг, 9 апреля 2020 г.

Как разбить код, чтобы MethodLength был хотя бы 15

#ruby_on_rails #ruby

                    
Есть консерн:

module Omniauthable
  extend ActiveSupport::Concern
  included do
    def self.find_for_oauth(auth)
      authorization = Authorization.where(provider: auth.provider, uid: auth.uid.to_s).first
      return authorization.user if authorization

      if auth.info.try(:email)
        email = auth.info[:email]
      else
        return false
      end

      user = User.where(email: email).first
      if user
        user.create_authorization(auth)
      else
        password = Devise.friendly_token[0, 20]
        user = User.new(email: email,
                        password: password,
                        password_confirmation: password)
        if user.valid?
          user.save!
          user.create_authorization(auth)
        else
          return false
        end
      end
      user
    end

    def create_authorization(auth)
      authorizations.create(provider: auth.provider, uid: auth.uid)
    end
  end
end


Нужно разделить self.find_for_oauth(auth), чтобы количество строк в методе было хотя
бы 15.
    


Ответы

Ответ 1



Я бы переписал так: module Omniauthable extend ActiveSupport::Concern included do def self.find_for_oauth(auth) authorization = Authorization.where(provider: auth.provider, uid: auth.uid.to_s).first if authorization authorization.user else @email = auth.info.try(:email) find_user # ищем пользователя create_user unless @user # если не находим, то создаем auth_user(auth) # пытаемся авторизовать и возвращаем либо nil либо пользователя end end def create_authorization(auth) authorizations.create(provider: auth.provider, uid: auth.uid) end private # скрываем служебные методы def self.find_user @user = User.where(email: @email).first if @email end def self.create_user password = Devise.friendly_token[0, 20] udata = { email: @email, password: password, password_confirmation: password } user = User.create(udata) # здесь происходит валидация и сохранение @user = user if user.errors.count == 0 # если после создания нет ошибок, то объявляем переменную экземпляра end def self.auth_user(auth) if @user # если в предыдущих методах был найден/создан пользователь, если @user = nil(не существует, то nil вернется из метода) @user.create_authorization(auth) @user end end end end

Ответ 2



Не злоупотребляйте культом Карго. Если какой-то код работает без разбивки, то пусть работает дальше.

суббота, 4 апреля 2020 г.

Возможности options_from_collection_for_select

#ruby_on_rails

                    
есть

.origin.select
  select#origin
    = options_from_collection_for_select(Airport.all, :id, :name)


HTML получается каким




Можно ли как то в options_from_collection_for_select для option задать отображение
не только по :name но и по нескольким полям типа так:

= options_from_collection_for_select(Airport.all, :id, ("#{:name} #{:city}(#{:country})")


Что бы получилось как то так



    


Ответы

Ответ 1



В классе, откуда вы извлекаете данные Airport следует реализовать метод, скажем full_name, который будет возвращать строку, эквивалентную той, которую вы хотите вызывать class Airport def full_name # Тут формируете нужный вам формат вывода "#{self.name} #{self.city}(#{self.country})" end end тогда вы можете вызвать этот новый метод, передав в третьем параметре символ с его именем .origin.select select#origin = options_from_collection_for_select(Airport .all, :id, :full_name)

Как правильно организовать базу данных

#база_данных #ruby_on_rails #activerecord

                    
Столкнулся с такой проблемой.
У отелей есть много услуг (например трансфер, парковка, интернет и т.д.), так же
у каждой комнаты в отеле могут быть разные услуги (минибар, балкон, вид на море/парк
и т.д.).
Получается что объект (отель или комната) предоставляют услуги. Связь многие ко многим.

Таблица будет выглядеть примерно так (составной внешний ключ)



А как связать модели?

class Service < ActiveRecord::Base
  has_many :service_in_object
  has_many :hotels, through: :service_in_object
end

class ServiceInObject < ActiveRecord::Base
  belongs_to :object #хмм
  belongs_to :service
end

class Hotel < ActiveRecord::Base
    has_many :rooms

  has_many :service_in_object
  has_many :service, through: :service_in_object
end

class Room < ActiveRecord::Base
    belongs_to :hotel

  has_many :service_in_object
  has_many :service, through: :service_in_object
end


Как правильно это организовать?
    


Ответы

Ответ 1



У вас получается полиморфная связь, которую нужно ввести при помощи ключевого слова polymorphic. Если не возражаете, я немного переделаю таблицу service_in_objects, чтобы избавиться от object - не очень хорошее название, давайте сделаем serviceable. Миграции для таблиц могут выглядеть следующим образом create_table :hotels, comment: "Оттели" do |t| t.string :title, comment: "Название" end create_table :rooms, comment: "Комнаты" do |t| t.string :title, comment: "Номер" t.integer :hotel_id, comment: "Внешний ключ для связи с оттелем" end create_table :services, comment: "Сервисы" do |t| t.string :title, comment: "Название" end create_table :service_in_objects, comment: "Промежуточная cвязующая таблица" do |t| t.integer :service_id, comment: "Внешний ключ для связи с сервисом" t.integer :serviceable_id, comment: "Внешний ключ для связи с оттелем или комнатой" t.string :serviceable_type, comment: "Внешний ключ для связи с оттелем или комнатой" end Тогда модели с учетом полиморфной связи через промежуточную таблицу service_in_objects могут принять следующий вид class Service < ActiveRecord::Base has_many :service_in_objects has_many \ :rooms, through: :service_in_objects, source: :serviceable, source_type: 'Room' has_many \ :hotels, through: :service_in_objects, source: :serviceable, source_type: 'Hotel' end class ServiceInObject < ActiveRecord::Base belongs_to :service belongs_to :serviceable, polymorphic: true end class Hotel < ActiveRecord::Base has_many :rooms has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end class Room < ActiveRecord::Base belongs_to :hotel has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end Убедиться в том, что полиморфная связь работает, можно при помощи сидов (db/seed.rb): ActiveRecord::Base.connection.execute('TRUNCATE hotels'); ActiveRecord::Base.connection.execute('TRUNCATE rooms'); ActiveRecord::Base.connection.execute('TRUNCATE services'); ActiveRecord::Base.connection.execute('TRUNCATE service_in_objects'); services = [{title: 'internet'}, {title: 'parking'}, {title: 'service1'}] Service.create services hotels = [{title: 'mariot'}, {title: 'hilton'}] Hotel.create hotels Hotel.all.each do |h| h.rooms.create [{title: '1'}, {title: '2'}, {title: '4'}] h.services << [Service.all.sample, Service.all.sample] h.save end Room.all.each do |r| r.services << [Service.all.sample, Service.all.sample] r.save end В реальном проекте настоятельно рекомендуется покрыть тестами хотя бы связи - у вас примере идущем с вопросом явные ошибки с единственным/множественным числом - тесты вас сильно выручат на данном этапе. Напортачить в связях не сложно, модели будут работать и со сломанными связями, только воспользоваться ими не получится и при этом сообщения об ошибках на сломанных связях не совсем очевидны. Обратите внимание: Связь belongs_to - всегда единственное число, has_many - всегда множественное число. Название таблиц - всегда множественное число, название моделей - всегда единственное число.

воскресенье, 15 марта 2020 г.

Почему перестал работать выход с сайта Rails (devise)?

#ruby_on_rails #devise


Здравствуйте, скажите пожалуйста как исправить ошибку. При выходе с сайта выкидывает
сообщение - Couldn't find Doctor with 'id'=sign_out и указывает на строку 

@doctor = Doctor.find(params[:id])


в контроллере 

class DoctorsController < ApplicationController
  before_action :set_doctor, only: [:show, :edit, :update, :destroy]
  def index
    @doctor = Doctor.all
  end

  def show
    @length =  User.where(doctor_id: params[:id]).size
  end

  private 

  def set_doctor
    @doctor = Doctor.find(params[:id])
  end
end


Раньше с сайта выходил, но теперь такая возможность пропала. Использую гем Devise

UPDATE
routes.rb

  Rails.application.routes.draw do
get 'contact/index'

resources :news
resources :prices
get 'healthy/index'
get 'about/index'

resources :users
resources :doctors

devise_for :doctors, :controllers => { registrations: 'registrations' }
root 'users#main'


end

Ссылка на выход из сессии

<%= link_to 'Вийти', destroy_doctor_session_path %>



    


Ответы

Ответ 1



Возьмите ваш маршрут GET /doctors/sign_out и смотрите по списку сверху вниз, по какому правилу он совпадёт первым. И совпадает он с GET /doctors/:id, собранным из resources :doctors. Почему не GET /doctors/sign_out (из devise_for), если он подходит лучше? А неважно, он первый подходящий. Он и используется. Решение простое — поместите вызов devise_for выше resources :doctors, тем самым изменив порядок этих маршрутов в списке так, чтобы первым совпадал GET /doctors/sign_out. Альтернативно, повышенной сложности: не меняя порядок, установите к параметру :id в маршруте требование состоять только из цифр, аналогично примеру из документации: get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ } Это единственный выход, когда маршруты сильно перекрываются. Это не ваш случай, в вашем случае достаточно изменить порядок. Но только первого приёма для разруливания таких проблем в общем случае недостаточно.

пятница, 13 марта 2020 г.

Rails - yml файл для всех языков

#ruby_on_rails #локализация #yml


Я переводил свое Rails-приложение и столкнулся со следуюшей проблемой. Не все элементы
надо переводить. Например, в en.yml у меня хранятся не только фразы, но и ссылки. Переводить
их не имеет смысла, но если их не включасть, например, в ru.yml, то будет ошибка translation_missing. 

@MichaelRadionov посоветовал использовать наследование. 

Соответственно, вопрос: Как использовать наследование в YML файлах
    


Ответы

Ответ 1



Использовать наследование не нужно. Эта функция уже включена в гем rails-i18n. Для того что-бы все работало, нужно отредактировать файл application.rb: # Автозагрузка всех языковых файлов config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # Дефолтовый язык config.i18n.default_locale = :ru # Возврат к английскому при ошибках config.i18n.fallbacks = [:en] # Так же можно указывать какой язык использовать при ошибках config.i18n.fallbacks = {'ru' => 'en'}

Проблема с миграцией базы данных на postgres

#ruby_on_rails #postgresql


При создании базы возникает следующая ошибка:

andrey@asus:~/project/odnogrupniki$ rake db:create:all
FATAL:  Peer authentication failed for user "odnogrupniki"


логи целиком: ТУТ

databse.yml:

default: &default
  adapter:  postgresql
  encoding: unicode
  pool: 5
  timeout: 5000
  username: 'odnogrupniki'
  password: '1111'

development:
  <<: *default
  database: odnogrupniki

test:
  <<: *default
  database: odnogrupniki_test

production:
  <<: *default
  database: odnogrupniki_production


в Gemfile добавлял: gem 'pg'
 Bundle - выполнял

andrey@asus:~/project/odnogrupniki$ psql --version
psql (PostgreSQL) 9.5.1


Пользователя создавал так:

postgres@asus:/home/andrey/project/odnogrupniki$ createuser odnogrupniki -P -S -R -D
Enter password for new role: 
Enter it again:

    


Ответы

Ответ 1



Локально можно настроиться на работу по peer athentication, но для этого в базе данных должен быть пользователь с таким же именем, какой у подключающегося логин в операционной системе. Для разработки это можно настроить максимально быстро на чистом дистрибутиве. Чтобы ActiveRecord подключался, удостоверяясь только с помощью учётной записи подключающегося через Unix domain socket, то надо убрать логин, пароль и хост из настроек подключения. Совсем. А сделать "себя" суперпользователем в БД на свежеустановленном PostgreSQL (когда пользователь там всего один, postgres) можно в одну команду: sudo -u postgres createuser --superuser $(whoami) \______________/ \______________________________/ Притворившись Создать суперпользователя с postgres именем, выведенным командой whoami А дальше обычное rake db:create и прочее. Плюсов у такого подхода хватает: Работает с настройками по умолчанию: установил, сделал себя-администратора и вперёд Учётные данные ни в какой момент не существуют в рабочем дереве На "боевом" сервере так делать не стоит, но это уже совсем другая история...

Ответ 2



Замените в конфигурационном файле pg_hba.conf метод аутентификации, вместо аутентификации по системным учетным записям local all postgres peer укажите аутентификацию по паролю local all postgres md5

понедельник, 9 марта 2020 г.

Uncaught TypeError: jQuery(…).datepicker is not a function

#javascript #jquery #ruby_on_rails #jquery_ui


В проекте написанном на ruby on rails установлна библиотека для jquery ui. 

На следующем скрипте через консоль гугл хром выдает ошибку 


  Uncaught TypeError: jQuery(...).datepicker is not a function





Полазив в интернете на форумах и поговорив с программистами, все говорят, что это
из конфликта скриптов. Где то два раза запускается один и тот же скрипт или конфликт имен. 

У меня вопрос следующий. Как и с помощью каких инструментов можно проверить где и
что именно конфликтует? Проект очень большой, толком понять где этот скрипт конфликтует
очень сложно. Заранее спасибо за ответ.   
    


Ответы

Ответ 1



Проблема была связана с конфликтом нескольких скриптов jquery. Через консоль хрома показала ошибку плагина. Удалил дублирующий и все стало на свои места.

воскресенье, 8 марта 2020 г.

Изображения пропадают с Heroku

#ruby_on_rails #ruby #heroku


Пользуюсь Paperclip. В девелопменте все ок, но на Хероку добавляю изображения к постам,
сначала все нормально - все грузит и показывает, но через какое-то время все изображения
пропадают - на их месте только названия файлов. В чем может быть проблема?

Heroku logs выдает что то про неполадки с путями:

2016-05-13T14:38:05.031223+00:00 heroku[router]: at=info method=GET path="/system/posts/images/000/000/007/medium/app-server-arena2.png?1463131430"
host=arcane-taiga-31170.herokuapp.com request_id=21181509-0382-494c-b4d8-fc0837464c99
fwd="92.100.233.26" dyno=web.1 connect=0ms service=4ms status=404 bytes=1789
2016-05-13T14:38:05.029499+00:00 app[web.1]: ActionController::RoutingError (No route
matches [GET] "/system/posts/images/000/000/007/medium/app-server-arena2.png"):
2016-05-13T14:38:05.027456+00:00 app[web.1]: Started GET "/system/posts/images/000/000/007/medium/app-server-arena2.png?1463131430"
for 92.100.233.26 at 2016-05-13 14:38:05 +0000

    


Ответы

Ответ 1



Да, Heroku так работает. Локальный диск у него "эфемерный" и может быть пересоздан из образа в любой момент. А именно, когда приложение "засыпает", его диск уничтожается, а когда " будят", создаётся новый, отдельный на каждую машинку (dyno). Поэтому на диск ничего, что предназначено для длительного хранения, сохранять нельзя. Нужно использовать внешнее хранилище. Можно сохранять прямо в БД (они не для этого предназначены, но в теории это реально), а можно подключить внешнюю службу хранения с доступом по HTTP вроде Amazon Simple Storage Service (S3), а можно придумать/найти что-то ещё.

rails puma постоянный рост используемой памяти

#ruby_on_rails #веб_сервер


Имеется небольшое приложение на rails(4.2.6), в качестве веб-сервера используется
nginx+puma(3.4.0). Сервер Debian 8.1 64bit. 
Заметил одну странную вещь, с каждым запросом, используемое процессами puma количество
памяти растет, и никогда не снижается(во время отсутствия каких либо запросов). Это
приводит к тому, что  ОЗУ на сервере (512 мб) заканчивается, и останавливается служба
postgres(9.4). Пробовал разное количество воркеров, нитей, работа в кластерном режиме
и в обычном - результат всегда один и тот же. После нескольких тяжелых запросов ОЗУ
заканчивается.
Неужели так и должно быть? Какие есть пути устранения такой проблемы? По информации,
которую я нашел, Puma - это один из лучших выборов для избежания проблемы медленных
клиентов и долгих запросов.
Текущий конфиг такой:

#!/usr/bin/env puma

...

threads 2,4

...
workers 1

preload_app!

on_restart do
  puts 'Refreshing Gemfile'
  ENV["BUNDLE_GEMFILE"] = "/home/.../current/Gemfile"
end

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

    


Ответы

Ответ 1



Описанное в ответе реально не совсем правда. GC может освобождать память, но темпы освобождения могут быть меньше темпов роста. Вне синтетических тестов обычно так и есть. Ответ подлежит переработке с учётом этого факта. Да, это из-за особенностей работы GC в самом Ruby. Он держит собственный пул памяти, увеличивая его при необходимости, но никогда не уменьшая. И тому есть причина. Объекты, "подметённые" сборщиком мусора, освобождают память с точки зрения интерпретатора, но не с точки зрения ОС. Посему, только тот факт, что память занята процессом, не означает, что в ней действительно есть что-то ценное для программы, скорее всего, это просто "запас", в котором интерпретатор будет размещать новые объекты сам, не дёргая аллокатор ОС. Соответственно, в каждый момент времени процесс будет занимать максимум того, что ему было нужно за всё время его жизни. Размер пула будет с небольшим запасом равен пиковому потреблению памяти. Беда с большими объектами в том, что они требуют большие последовательные области памяти. И если такой блок в пуле не находится, то... пул ещё увеличивается на такую величину, чтобы большой объект влез! Эту проблему можно было б частично победить, используя сборщик мусора с "уплотнением" (compaction), когда GC в процессе работы "перекладывает" мелкие объекты поближе друг к другу, тем самым образуя более крупные последовательные области свободной памяти. Это же могло бы позволить отдавать крупные "хвосты" незанятой памяти обратно в ОС. Но это здорово усложняет работу С-шных расширений, которые запоминают, где был объект, непосредственно по адресу в памяти. Нельзя просто сказать им "я вон тот объект подвинул, имей в виду". Сделать можно много чего. Пол-гигабайта на целое рельсовое приложение и хранилища данных это... крайне немного. Есть смысл добавить, если не физической ОЗУ, то хотя бы подкачки. Подкрутить garbage collector на более осторожное расширение пула и частые срабатывания. Это вряд ли поможет, но может немножко отсрочить неизбежное. Это довольно обширная и опасная тема, требующая тщательного стресс-тестирования на каждое изменение. (Самый богатый на приключения) Реально снизить пиковое потребление памяти, отдавая большие ответы по кусочкам, чтобы GC успевал подчищать то, что уже отослано клиенту. Есть ActionController::Live, с помощью которого можно писать ответ в поток по кусочкам, не загружая все исходные данные для него в память.

Как использовать attr_accessible в Rails 5?

#ruby_on_rails


Как использовать attr_accessible (может есть аналог) в Rails 5? Гем protected_attributes
не работает, так как есть конфликт с версиями activemodel и activerecord. Заранее спасибо.
    


Ответы

Ответ 1



Данный атрибут не работает в современных версиях фреймворка Ruby on Rails. Ранее он использовался для того, чтобы на уроне модели явно задать атрибуты, которые можно будет "массово" редактировать на уровне контроллера (т.е. в группе параметров, которые поступают из формы). Данная практика признана неудачной, во-первых вы неявно разрешаете возможность редактирования для всех контроллеров, которых может быть много (как минимум приложение и система администрирования), во-вторых вы на уровне модели явно выдаете разрешения, которые должны выдаваться в уровне контроллера. В третьих слишком вольное использование этого атрибута (и для backend и для frontend частей приложения) приводило к уязвимостям приложений, когда с frontend-части можно было путем манипуляций содержимым POST-содержимого менять те параметры модели, которые не разрешено менять с frontend-части, но которые были разрешены в attr_accessible например для backend-части сайта. Начиная с версии Ruby on Rails 4, для разрешение присвоения параметров текущей модели было перемещено с уровня моделей на уровень контроллера. Теперь вам нужно явно указать какие параметры разрешено изменять в модели на уровне контроллера. Например, один из возможных вариантов может выглядеть так class SomeController < Admin::ApplicationController ... def create resource = Resourse.new resource.assign_attributes(resoure_params) if resource.save redirect_to index_page else render resource.new_record? ? :new : :edit end end ... private def resourse_params [ :id, :name, :weight ] end ... end или можно явно пройтись по параметрам, отметить при помощи метода permit те, которые можно передавать модели и воспользоваться например методом create class SomeController < Admin::ApplicationController ... def create if Resourse.create resource_params redirect_to index_page else render resource.new_record? ? :new : :edit end end ... private def resource_params params.require(:resource).permit(:id, :name, :weight) end ... end

Когда может быть полезна команда rake db:schema:load?

#ruby_on_rails


В Rails есть команда rake db:schema:load. Когда она может быть полезна, в каких случаях
ее применять?
    


Ответы

Ответ 1



Команда полезна, если вам нужно одним махом выставить структуру в базе данных такую же, как в schema.rb или schema.sql вашего проекта. Обычно структура БД модифицируется через миграции и rake db:migrate. Такой способ хорош по трем причинам: Инкрементальное изменение БД - накатываются только те миграции, которые еще не накатывались на текущую БД; Нет угрозы потери существующих данных - в уже существующие таблицы и данные в них не вносятся изменения, если только это явно не указано в новых миграциях; Возможность отката на n миграций назад - с помощью rake db:rollback. При этом также обновляется файл schema.rb. После последовательной накатки всех миграций, в этом файле будет структура, отражающая все изменения через миграции, от самой первой до самой последней из накатанных. И, по-хорошему, этот файл нужно коммитить в git наряду с другими файлами проекта. Теперь представим ситуацию: В проекте заведены несколько веток, на несколько разных фич; В каждой ветке, так или иначе, оказалось нужно модифицировать структуру БД; Значит в каждой ветке есть какие-то свои миграции; Мы находимся в ветке A, создали в ней миграции, накатили их - изменили структуру БД; Внезапно нам понадобилось перейти на ветку Б и что-то сделать там; Мы перескакиваем на нее с помощью git checkout Б; Теперь в редакторе мы видим код ветки Б, и можем с ним работать; Но в БД осталась структура данных, созданная за счет миграций из ветки А. Вот такой конфликт. В идеале нам нужно убрать из БД все таблицы, поля и индексы, созданные миграциями из ветки А, перейти на ветку Б, и накатить все миграции из ветки Б. Примерно так: rake db:rollback - n-раз, чтобы откатить n-миграций; git checkout Б; rake db:migrate. А когда мы все сделаем в ветке Б и захотим вернуться в ветку А - нам понадобиться снова проделать эту последовательность операций. Откатить все миграции ветки Б, перейти на ветку А, и накатить все миграции ветки А. rake db:schema:load помогает избавиться от этого. Дело в том, что в каждой ветке, когда мы создавали миграции, накатывали их и делали коммит - мы коммитили также и файл schema.rb. Значит, если мы с ветки А перейдем в ветку Б - мы увидим, что структура в schema.rb соответствует ровно тем миграциям, которые должны применяться в ветке Б. И мы можем эту структуру просто загрузить в БД. В итоге - алгоритм перехода с ветки на ветку упрощается до: git checkout Любая-ветка rake db:schema:load Но остается нюанс. Так как db:schema:load, по сути, накатывает готовую структуру на базу данных с нуля - все существующие таблицы, и, что важно нам, данные в таблицах - удаляются. То есть на выходе мы получаем, пусть и БД с актуальной структурой, но без данных. И накатывание этих данные нам нужно продумывать отдельно. Один из вариантов - хранить накатку данных в seeds.rb и после перехода на другую ветку и применения rake db:schema:load применять также rake db:seed.

Ответ 2



Она может быть полезна в том случае, если вам требуется воссоздать структуру базы данных в другом окружении/базе, не задействуя миграции (допустим по той причине, что они выполняются слишком долго). Например, для тестового окружения вы можете выполнить команду rake db:test:load и в тестовой базе данных будет развернута текущая схема из db/schema.rb, без последовательного выполнения миграций. Это становится особенно важно в том случае, когда вы работаете в контейнерах и прогоны тестов у вас начинаются каждый раз с чистой базы данных, а схлапывать старые миграции (заменяя их содержимым schema.rb) вы в силу каких-то причин не хотите (например, у вас там хранятся комментарии по причинам выбора индекса).

вторник, 25 февраля 2020 г.

Как установить плагин для RoR в RubyMine?

#github #ide #ruby #ruby_on_rails


Точнее, как выполнить эту строку из руководства?
$ script/plugin install git://github.com/technoweenie/restful-authentication.git

Или как это можно сделать не в IDE, если так будет удобнее?    


Ответы

Ответ 1



Добавьте в Gemfile: gem "restful-authentication" И RubyMine сама выполнит bundle install

Ответ 2



Руководство вероятно для 2.3-style rails. Вкладка Tools | Run Rails Script Клац на "..." и выбираем установку плагина Добавьте специфичные аргументы если требуется

Ответ 3



Иногда возникает потребность установки двух версий одного и того же гема, для этого открываешь терминал (вкладка обычно находится в левом нижнем углу RubyMine) и устанавливаешь командами: gem install some_gem -v 1.0 gem install some_gem -v 2.0 ну и там же проверяешь командой: gem list some_gem на выходе будет что-то типа *** LOCAL GEMS *** some_gem (1.0, 2.0)

понедельник, 24 февраля 2020 г.

Rails не видит введенных в форме данных

#ruby_on_rails #devise


У меня сразу несколько вопросов:


Добавил в Devise атрибуты name (string) и phone (integer). При отправке формы выдает
ошибки "Name can't be blank" и "Phone can't be blank", хотя поля заполнены.
Как заменить лэйблы (например, перевести на русский)? Когда меняю :name на :ФИО -
все нормально, но когда меняю остальные - выдает ошибку.


Сама форма:

<%= form_for(resource, :as => resource_name, 
                         :url => registration_path(resource_name), 
                         :html => { :role => 'form'}) do |f| %>
    

Регистрация

<%= devise_error_messages! %>
<%= f.label :name %>
<%= f.text_field :name, autofocus: true %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :phone %>
<%= f.text_field :phone %>
<%= f.label :password %> <%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit 'Sign up', :class => 'button right' %> <% end %>


Ответы

Ответ 1



Добавил в Devise атрибуты name (string) и phone (integer). При отправке формы выдает ошибки "Name can't be blank" и "Phone can't be blank", хотя поля заполнены. Скорее всего, вы наступили на те же грабли, что и я когда-то, забыв про Strong Parameters. Как заменить лэйблы (например перевести на русский)? Когда меняю :name на :ФИО - все нормально, но когда меняю остальные - выдает ошибку. Разумеется, выдаёт. Надо 'ФИО', а не :ФИО и так далее. С двоеточия начинаются ключи, а вам надо задать конкретное строковое значение. Однако, если вы собираетесь именно переводить, то лучше сразу начинать использовать API интернационализации.

В каких случаях стоит, а в каких - нет, использовать TDD? Чем опасно его не использовать? [закрыт]

#ruby_on_rails #веб_программирование #test_driven_development


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 3 года назад.
                                                                                
           
                
        
Никак не могу понять, как TDD сумел обрести такую популярность. Почему? Потому что
я считаю это максимально иррациональным подходом к разработке:


Ты должен написать тест, который заведомо провалится.
Трата времени. Ты не написал ни одной строчки кода, зато написал 20 строк кода, чтобы
убедиться в том, что то, чего ты не написал, не работает.
Ты должен написать тест, который реализует твои мысли относительно того, как это
должно работать.
Трата времени. За то время, пока ты реализовывал свои мысли в строках теста, ты мог
реализовать свои мысли строками кода.
Ты должен написать код так, чтобы он прошел написанный тест.
А в это время ты уже мог заниматься рефакторингом написанного кода.
Рефакторинг.




Еще одна особенность. Как мы знаем, веб-разработка предполагает разработку того,
с чем конечный пользователь будет взаимодействовать через браузер. Подход TDD предполагает
максимальное абстрагирование от браузера и использование для проверки работоспособности
кода только командную строку. Чувствуете этот запах? Так пахнет логика.  



Чтобы мои слова не звучали необоснованно, я приведу вам пример того, как я пытался
освоить данную ветвь.  

Изначально я знал, что люди с нелюбовью относятся к имеющемуся в rails стандартному
test-фреймворку. И я также прекрасно знал, что подавляющее большинство предпочитает
ему использование Rspec.

Первым делом я, конечно же, решил ознакомиться с документацией по Rspec. По первой
же ссылке в гугле я попал на эту страницу. Красивый landing-page с кучей видео разряда
ни о чем. Окей, почитаю документацию, решил я. Абсолютно ничего дельного эта страница
мне не принесла. Лишь внизу красовалась ссылка на какой-то Relish. Что это такое и
каким боком оно относится к Rspec - непонятно. Ладно, переходим.
Только оттуда с непримечательной ссылки Rspec-core (догадайся 2) я попал на нечто,
что хоть как-то похоже на то, что я ищу. Какие-то примеры кода. Да, сразу код. Не понятно,
как установить, какая структура должна быть у папок, как нужно именовать файлы, как
запускать - ничего.  

Спустя день, перелопатив кучу инфы по этому поводу, я узнал, куда стоит класть файлы,
как именовать папки, что require-ить, какие методы использовать (базу). Помогли мне
в этом довольно полезные скринкасты (на которых, кстати говоря, было полностью разработано
приложение без использования тестов, а тесты писались "в обучающих нас целях", когда
все уже заведомо работало так, как надо, и в данном случае тесты подгонялись под код,
а не наоборот (как это предполагает TDD), что еще раз доказывает нам ненадобность использования
оного). Не было ни какой конкретной инфы (в виде гайда, как это сделано в случае rails,
или хотя бы общей спарвки) ни на хабре, ни на railscasts (даже с pro-подпиской), на
которых R. Bates в своей привычной манере "проскакал" по верхам, показав типичный пример
из ряда "сделайте так-то, у меня получилось так-то, на это до свидания".

Садимся писать. Создаем приложение, устанавливаем необходимые гемы, пишем. Решил
я начать по-порядку. Роутинг. Написал тесты, которые должны были заведомо провалиться.
Провалились не тесты, а сам Rspec. Оказалось, ошибка синтаксиса (правильно, я же еще
должен знать, как писать). Тратим время на поиск примеров. Реализуем. Тесты провалились.
Реализовываем код (а что там реализовывать? Написал необходимые мне пути). Тесты прошли.
На все про все у меня ушло около 3-х часов. За это время я бы успел реализовать не
только логику routing'а, но и логику модели и отчасти каких-то контроллеров.  

Решил заняться написанием контроллеров. Опять уперся в банальное незнание и неумение
пользоваться новым инструментом. Как человек наученный каким-то опытом, не стал проклинать
в этом всех и вся, а просто полез в документацию. Окей, гугл, "rspec controller". Это
все, что нам предоставляет, насколько я понял, официальная документация. Опять же этот
Relish. На этом этапе я матюкнулся, послал все к чертям и решил немного отдохнуть.
Теперь, отдухнув, пишу сюда. И нет, пишу я не с целью выговориться или в очередной
раз, но уже на публику, проклясть этот TDD, а разобраться.  

Да, даже несмотря на все мои неудачи, я хочу разобраться, во-первых, в том, почему
же этот TDD так популярен? Почему все "настоятельно рекомендуют закрыть браузер и написать
парочку тестов", когда можно спокойно (и даже более полезно для себя с точки зрения
психики) обойтись простым визитом на localhost:3000? Что движет всеми теми, кто так
усердно (если такие вообще есть, и это не просто показуха) использует TDD? И самое
главное: в чем опасность отказа от этого подхода? Может ли отказ как-то сказаться на
твоем резюме или в поиске работы?  

Если есть действительно весомые аргументы против моей точки зрения, то прошу подкрепить
свой ответ ссылками на обучающие материалы по этой теме (желательно от и до, подкрепленные
real-life примерами и охватывающие хотя бы половину из того, с чем можно столкнуться
при реальном использовании).

Спасибо тем, кто осилил. Заранее извиняюсь, если это оскорбило чьи-то чувства. Предполагается,
что все, что написано выше - ИМХО.
    


Ответы

Ответ 1



Здесь есть три составляющие: Во-первых, сами тесты. Они нужны, в первую очередь, чтобы при дальнейшем изменении приложения не ломался старый функционал. Понятно, что, если приложение достаточно маленькое, быстрее и приятнее прокликать всё руками. Но с каждой новой фичой такое прокликивание будет занимать всё больше времени. К тому же, какие-то кейсы могут быть забыты. Автотесты же помогают прогнать тесты быстро и минимизировать человеческий фактор. В итоге, появляется возможность использовать CI. RSpec, в основном, подразумевает написание модульных тестов. Однако можно использовать, например Cucumber - тесты больше похожи на привычное "прокликать". Но, при этом, сами сценарии тестов становятся сложнее, т.к. сразу нужно проверить гораздо больше кейсов. Во-вторых, TDD. Пожалуй, в рамках TDD тесты понятнее будет называть спецификациями (specifications, specs - в RSpec). По сути, это текст задания, написанный в понятном для интерпретатора виде. На сколько написание спецификаций до кода себя оправдывает - один из холиваров. В любом случае, автотесты нужны. А в какой момент их писать - решать тебе. Лично мне было сложно писать "test first" (да и "last") до знакомства с принципами SOLID. Но, теперь, как сайд-эффект, мне легче проектировать архитектуру классов. Специфика RSspec такова, что легче тестировать солидные классы. (Спеки для несолидных получаются длинные, с кучей стабов и моков.). Судя по статье в вики, не я один отметил этот эффект: Разработка через тестирование предлагает больше, чем просто проверку корректности, она также влияет на дизайн программы. Разработка через тестирование способствует более модульному, гибкому и расширяемому коду. В-третьих, RSpec. Как я уже говорил, это не единственный фреймворк для написание тестов. На сколько я понял, основные проблемы возникли именно из-за его незнания. Но это не делает его "плохим". Писать быстро на незнакомом фреймворке вряд ли получится хоть у кого-то. Да, написание тестов, как и любого другого кода, занимает дополнительное время. Но обычно, всё же, это не 3 часа вместо 15 минут. В твоём же случае, это были затраты на обучение а не написание. Кстати, я в первый раз вижу, чтобы тестировали роуты. Обычно не требуется покрытие всего кода тестами. Корректность части компонентов (например тех же роутов) будет очевидна из корректности остальных компонентов. Ну и на практике, TDD хорошо подходит для крупных проектов, в которых проектирование на должном уровне. Для стартапов, функционал которых не очень велик, зато очень часты изменения - может быть излишним. Для лендингов, весь бэкенд сводится к отправки email с введённым пользователем телефоном - тоже.

Ответ 2



Надо понимать на что и как писать тесты, в каждом проекте может быть очень важный участок, внесение изменений в который очень критично - например модуль для подсчета денежной информации, так и участок менее важный - например ui админки сайта. А так, навскидку: Поддерживаемость - Тесты нужны, например, если вы собираетесь без боли рефакторить код, потом, через год, или не вы. Модульность, принцип единой ответственности - TDD вынуждает разработчика писать чище и проще, заранее придумывать апи, держать цикломатическую сложность в тонусе.

четверг, 13 февраля 2020 г.

Развертывание Rails приложения на хостинге

#ruby_on_rails


Как развернуть Rails приложение на VPS сервере? Нужно ли что-то дополнительно устанавливать
на сервере, кроме самого Rails?

Что было сделано: 


Установлен Rails на VPS
Загружено на сервер нужное rails приложение
После чего через консоль запустил само приложение cd appname , rails s


Как получить к нему доступ из вне? То есть через URL или IP адрес в браузере?
    


Ответы

Ответ 1



В последних версиях Rails, где-то около 4.0 и выше — никак, потому что вебсервер вешается по умолчанию на localhost:3000 и принимает соединения только через "локальную петлю", от самого себя к самому себе. Для нужд разработки этого достаточно, да и в production-средах в большинстве случаев тоже (из-за балансировщика нагрузки; но тоже не всегда). Надеюсь, вы уже заменили Webrick на что-то более серьёзное. Webrick написан на чистом Ruby и работает одним процессом в один поток. Он даже одного пользователя будет выдерживать с трудом. Как правило, сервер приложения, запускаемый таким образом, не приспособлен для работы "лицом в интернет" (неэффективен, мало возможностей настройки), поэтому его разворачивают за прозрачным прокси (обычно nginx), который принимает соединения напрямую и обслуживает самостоятельно запросы на статические файлы, а остальное перенаправляет к серверу приложения. Тема достаточно обширная и гайдов на просторах интернета очень много, очень разного качества, и я не рискну писать ещё один здесь. Я изложу общий план действий, а их конкретную реализацию можно придумать и самостоятельно: Заставить сервер приложения слушать сетевой адрес/порт, доступный локально (или адрес/порт с ограниченным доступом, или вовсе Unix domain socket) Поставить перед сервером приложения балансировщик нагпузки/прозрачный прокси и организовать раздачу статики (что сервер приложения обычно делает неэффективно) Например, поставить nginx и сделать ему try_files на статику и proxy_pass на локальную точку, которую слушает сервер приложения Обеспечить выживание: воспользоваться любым решением, которое будет автоматически запускать приложение при запуске машины (чтобы после перезагрузки приложение запускалось без лишних движений), а также перезапускало его в случае падения. Но это очень примитивный сценарий, который не для всех приложений подойдёт. Есть целый род деятельности по планированию и реализации инфраструктуры. Я совершенно никак не затронул: Отслеживание признаков жизни сервера Сбор ошибок и уведомление о них разработчиков Резервные копии Процесс автоматического разворачивания ...а это всё весьма нужные вещи. Есть также более весёлые варианты вроде сборки Docker-образа из приложения и запуск его в виде отдельного контейнера. Но итоговая система будет приблизительно такой же. Есть определённая свобода вроде "делать ли nginx отдельным контейнером".

Ответ 2



В списке установленного ещё забыли сам Ruby) я использую связку apache+passenger для своих приложений. Для passenger очень неплохая документация, если надумаете использовать, только сразу ограничте ему потоки, а то приложение будет падать из за нехватки памяти.

среда, 5 февраля 2020 г.

Когда использовать path в link_to?

#ruby_on_rails


<% @products.each do |product| %>
  <%= link_to 'Show', product %>
  <%= link_to 'Edit', edit_product_path(product) %>
  <%= link_to 'Destroy', product, method: :delete,
                  data: { confirm: 'Are you sure?' } %>
<% end %>


<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>


Почему для show и destroy не используется product_path, а в оcтальных случаях path
используется
    


Ответы

Ответ 1



Если в рельсовый хелпер link_to передать в качестве параметра ресурс (например, объект ActiveRecord) - хелпер сам построит путь до него. Для этого link_to передает параметры в метод url_for, который строит путь по указанным параметрам. Например: <%= link_to 'Show', product %> вернет путь /products/1, где 1 - это id ресурса. А если указать массив вида [:admin, product] - это создаст ссылку на /admin/products/1. А если - массив вида [:admin, :products] - создаст ссылку на /admin/products. Подобным образом вы можете задавать ссылки и в контроллерах, например, redirect_to [:edit, product] В итоге в ваших вьюхах вы можете заменить... <%= link_to 'Edit', edit_product_path(@product) %> | <%= link_to 'Back', products_path %> ...на... <%= link_to 'Edit', [:edit, @product] %> | <%= link_to 'Back', :products %> ...и результат не изменится.

Ответ 2



Маршруты, выдаваемые рельсовым хелпером resources, можно разделить на две группы: Прямые действия (запрос с которым осмысленен с точки зрения семантики HTTP): index: GET коллекции create: POST ресурса show: GET ресурса update: PATCH ресурса (или PUT, хотя правильность семантики Rails тут под вопросом) destroy: DELETE ресурса ...и вспомогательные заглушки, которые нужны исключительно потому, что "надо рассказать браузеру, как совершить действие": new: интерфейс к create edit: интерфейс к update Прямые действия используют просто путь к тому, над чем производится действие, а само действие опознаётся из HTTP-метода. Но для "заглушек" осмысленных HTTP-методов нет, поэтому они используют пути "с хвостиком". А поскольку хелпер возвращает только путь (но не метод!), для прямых действий путь можно собрать прямо их объекта ресурса, а для заглушек нужен хелпер или объект с "подсказкой". Поскольку форма "подсказок" у маршрутной системы малоизвестна и имеет очень неочевидный синтаксис, её часто избегают в пользу хелперов, но это вопрос стиля.

Ответ 3



Вообще хэлпер link_to принимает путь, который можно получить при помощи path-хэлперов. Однако в том случае, когда редактируется или удаляется один объект ActionPack может автоматически сформировать путь. Ничто не мешает вам использовать хэлепер и в этом случае <%= link_to 'Show', product_path(product) %> Однако так получается длиннее.

пятница, 31 января 2020 г.

Вопрос про админки в Ruby On Rails

#ruby_on_rails


Здравствуйте, нужно понять, какая сейчас админка:

1) поддерживает Ruby On Rails последней версии под номером 4.2

2) русифицированная, вместе с ошибками валидации, либо понять как это сделать максимально
просто и быстро и какими gem'ами нужно догнаться
    


Ответы

Ответ 1



Хорошая админка - это Active Admin. Active admin документация Все это ставится с гемом Devise. С моей версией ruby 2.2.1 версия Devise gem 'devise', '~> 3.4.1' хороший туториал по настройке Devise В итоге в гем файле должно выглядеть как-то так: gem 'activeadmin', github: 'activeadmin' gem 'devise', '~> 3.4.1'

Ответ 2



Я в большинстве проектов использую https://github.com/activeadmin/activeadmin Работает в содружестве с гемом devise, поэтому его также придётся добавить в Gemfile

Ответ 3



Еще есть очень простая и удобная админка rails_admin: https://github.com/sferik/rails_admin Интегрируется с Devise (для регистрации и аутентификации), Papertail (для хранения истории изменений) и Cancan (для разделения прав пользователей)