rocket_cms 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +2 -0
- data/.travis.yml +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +36 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/head.load.js +707 -0
- data/app/assets/javascripts/jquery.placeholder.js +157 -0
- data/app/assets/javascripts/rocket_cms.js.coffee +10 -0
- data/app/assets/javascripts/rocket_cms/flash.js.coffee +3 -0
- data/app/assets/javascripts/rocket_cms/map.js.coffee +22 -0
- data/app/assets/stylesheets/rocket_cms.css.sass +2 -0
- data/app/assets/stylesheets/rocket_cms/flash.css.sass +66 -0
- data/app/assets/stylesheets/rocket_cms/normalize.css.scss +406 -0
- data/app/controllers/concerns/no_cache.rb +12 -0
- data/app/controllers/concerns/rs_errors.rb +58 -0
- data/app/controllers/concerns/rs_menu.rb +45 -0
- data/app/controllers/concerns/rs_pages.rb +41 -0
- data/app/controllers/contacts_controller.rb +29 -0
- data/app/controllers/news_controller.rb +22 -0
- data/app/controllers/pages_controller.rb +12 -0
- data/app/controllers/search_controller.rb +25 -0
- data/app/mailers/contact_mailer.rb +15 -0
- data/app/models/ckeditor/asset.rb +5 -0
- data/app/models/ckeditor/attachment_file.rb +15 -0
- data/app/models/ckeditor/picture.rb +16 -0
- data/app/models/concerns/boolean_field.rb +9 -0
- data/app/models/concerns/enableable.rb +8 -0
- data/app/models/concerns/geocodeable.rb +4 -0
- data/app/models/concerns/manual_slug.rb +38 -0
- data/app/models/concerns/mappable.rb +77 -0
- data/app/models/concerns/seoable.rb +35 -0
- data/app/models/concerns/sort_field.rb +12 -0
- data/app/models/concerns/sortable.rb +8 -0
- data/app/models/concerns/trackable.rb +8 -0
- data/app/models/contact_message.rb +6 -0
- data/app/models/menu.rb +6 -0
- data/app/models/news.rb +5 -0
- data/app/models/page.rb +6 -0
- data/app/views/contact_mailer/new_message_email.html.haml +15 -0
- data/app/views/contacts/new.html.haml +10 -0
- data/app/views/contacts/sent.html.haml +4 -0
- data/app/views/errors/_base.html.haml +3 -0
- data/app/views/errors/error_403.html.haml +1 -0
- data/app/views/errors/error_404.html.haml +1 -0
- data/app/views/errors/error_500.html.haml +1 -0
- data/app/views/news/index.html.haml +8 -0
- data/app/views/news/show.html.haml +8 -0
- data/app/views/pages/show.html.haml +1 -0
- data/app/views/rails_admin/main/_check_boxes.html.haml +27 -0
- data/app/views/rails_admin/main/_form_raw.html.haml +1 -0
- data/app/views/search/index.html.haml +19 -0
- data/app/views/shared/_admin_link.html.haml +3 -0
- data/app/views/shared/_messages.html.haml +7 -0
- data/app/views/shared/_meta.html.haml +6 -0
- data/app/views/shared/_obj.html.haml +14 -0
- data/app/views/shared/_og.html.haml +4 -0
- data/config/locales/en.rocket_admin.yml +6 -0
- data/config/locales/en.rs.yml +17 -0
- data/config/locales/ru.cancan.yml +4 -0
- data/config/locales/ru.devise.yml +65 -0
- data/config/locales/ru.kaminari.yml +17 -0
- data/config/locales/ru.models.yml +78 -0
- data/config/locales/ru.mongoid.yml +450 -0
- data/config/locales/ru.rails_admin.yml +147 -0
- data/config/locales/ru.rocket_admin.yml +6 -0
- data/config/locales/ru.rs.yml +17 -0
- data/config/locales/ru.simple_captcha.yml +3 -0
- data/config/locales/ru.simple_form.yml +9 -0
- data/lib/filename_to_slug.rb +32 -0
- data/lib/generators/rocket_cms/admin_generator.rb +20 -0
- data/lib/generators/rocket_cms/templates/ability.erb +17 -0
- data/lib/generators/rocket_cms/templates/admin.erb +71 -0
- data/lib/generators/rocket_cms/utils.rb +22 -0
- data/lib/history_tracker.rb +4 -0
- data/lib/rails_admin/custom_show_in_app.rb +39 -0
- data/lib/rocket_cms.rb +57 -0
- data/lib/rocket_cms/admin.rb +128 -0
- data/lib/rocket_cms/configuration.rb +54 -0
- data/lib/rocket_cms/controller.rb +24 -0
- data/lib/rocket_cms/elastic_search.rb +32 -0
- data/lib/rocket_cms/engine.rb +4 -0
- data/lib/rocket_cms/model.rb +16 -0
- data/lib/rocket_cms/models/contact_message.rb +37 -0
- data/lib/rocket_cms/models/menu.rb +16 -0
- data/lib/rocket_cms/models/news.rb +61 -0
- data/lib/rocket_cms/models/page.rb +86 -0
- data/lib/rocket_cms/patch.rb +58 -0
- data/lib/rocket_cms/rails_admin_menu.rb +137 -0
- data/lib/rocket_cms/railtie.rb +39 -0
- data/lib/rocket_cms/tasks.rb +14 -0
- data/lib/rocket_cms/version.rb +3 -0
- data/lib/smart_excerpt.rb +98 -0
- data/rocket_cms.gemspec +50 -0
- metadata +533 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module Seoable
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
include Mongoid::Paperclip
|
4
|
+
|
5
|
+
included do
|
6
|
+
field :name, type: String
|
7
|
+
field :h1, type: String
|
8
|
+
|
9
|
+
field :title, type: String
|
10
|
+
field :keywords, type: String
|
11
|
+
field :description, type: String
|
12
|
+
field :robots, type: String
|
13
|
+
|
14
|
+
field :og_title, type: String
|
15
|
+
has_mongoid_attached_file :og_image, styles: {thumb: "800x600>"}
|
16
|
+
end
|
17
|
+
|
18
|
+
def page_title
|
19
|
+
title.blank? ? name : title
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_og_title
|
23
|
+
og_title.blank? ? name : og_title
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.admin
|
27
|
+
RocketCMS.seo_config
|
28
|
+
end
|
29
|
+
|
30
|
+
# deprecated
|
31
|
+
def self.seo_config
|
32
|
+
RocketCMS.seo_config
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module SortField
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
def sort_field(prefix = '')
|
6
|
+
prefix = "#{prefix}_" unless prefix == ''
|
7
|
+
|
8
|
+
field "#{prefix}sort".to_sym, type: Integer
|
9
|
+
scope "#{prefix}sorted".to_sym, -> { asc("#{prefix}sort".to_sym) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/app/models/menu.rb
ADDED
data/app/models/news.rb
ADDED
data/app/models/page.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
- excluded_column_names = %w[id created_at updated_at _id _type enabled attachment c_at u_at captcha captcha_key version modifier modifier_id]
|
3
|
+
|
4
|
+
%h3 Сообщение из формы связи:
|
5
|
+
|
6
|
+
%table
|
7
|
+
%tr
|
8
|
+
%th(style='padding: 2px 3px') Поле
|
9
|
+
%th(style='padding: 2px 3px') Значение
|
10
|
+
- ContactMessage.fields.keys.reject{|c| excluded_column_names.include?(c) }.each do |c|
|
11
|
+
%tr
|
12
|
+
%td(style='padding: 2px 3px')
|
13
|
+
= ContactMessage.human_attribute_name(c)
|
14
|
+
%td(style='padding: 2px 3px')
|
15
|
+
= @message.send(c.to_sym)
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'errors/base', code: 403, text: 'Доступ запрещен'
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'errors/base', code: 404, text: 'Запрашиваемая страница была удалена, или введён некорректный адрес'
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'errors/base', code: 500, text: 'Внутренняя ошибка сервера'
|
@@ -0,0 +1,8 @@
|
|
1
|
+
.rs-news-index
|
2
|
+
%h1= t('rs.news')
|
3
|
+
- @news.each do |news|
|
4
|
+
.rs-news-date= news.time.strftime('%Y-%m-%d')
|
5
|
+
- unless RocketCMS.configuration.news_image_styles.nil?
|
6
|
+
.rs-news-image= image_tag news.image.url(:full)
|
7
|
+
.rs-news-excerpt = news.excerpt
|
8
|
+
= paginate @news
|
@@ -0,0 +1,8 @@
|
|
1
|
+
.rs-news-show
|
2
|
+
%h1.rs-news-title= @news.name
|
3
|
+
.rs-news-date= @news.time.strftime('%Y-%m-%d')
|
4
|
+
.rs-news-text = @news.excerpt
|
5
|
+
- unless RocketCMS.configuration.news_image_styles.nil?
|
6
|
+
.rs-news-image= image_tag @news.image.url(:full)
|
7
|
+
.rs-news-content
|
8
|
+
= render 'shared/obj', obj: @news
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'shared/obj', obj: @seo_page
|
@@ -0,0 +1,27 @@
|
|
1
|
+
- if params[:associations].nil?
|
2
|
+
= form.collection_check_boxes field.method_name, form.object.class.send(field.method_name).values.map { |v| [t("enumerize.#{form.object.class.name.downcase}.#{field.method_name}.#{v}"), v] }, :last, :first, {}, {} { |i| i.label( class: 'checkbox' ) { i.check_box + i.text } }
|
3
|
+
- else
|
4
|
+
:ruby
|
5
|
+
related_id = params[:associations] && params[:associations][field.name.to_s]
|
6
|
+
config = field.associated_model_config
|
7
|
+
source_abstract_model = RailsAdmin.config(form.object.class).abstract_model
|
8
|
+
|
9
|
+
if form.object.new_record? && related_id.present? && related_id != 'new'
|
10
|
+
selected = [config.abstract_model.get(related_id)]
|
11
|
+
else
|
12
|
+
selected = form.object.send(field.name)
|
13
|
+
end
|
14
|
+
selected_ids = selected.map{|s| s.send(field.associated_primary_key)}
|
15
|
+
|
16
|
+
current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update'
|
17
|
+
|
18
|
+
xhr = !field.associated_collection_cache_all
|
19
|
+
|
20
|
+
collection = if xhr
|
21
|
+
selected.map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
|
22
|
+
else
|
23
|
+
i = 0
|
24
|
+
controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
|
25
|
+
end
|
26
|
+
|
27
|
+
= form.collection_check_boxes field.method_name, collection, :last, :first, {}, {} { |i| i.label( class: 'checkbox' ) { i.check_box + i.text } }
|
@@ -0,0 +1 @@
|
|
1
|
+
= field.pretty_value
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.rs-search-results
|
2
|
+
%h1 Результаты поиска
|
3
|
+
= form_tag search_path, method: :get, class: 'nav_search' do
|
4
|
+
= text_field_tag 'query', params[:query], placeholder: "Поиск"
|
5
|
+
= submit_tag 'Найти'
|
6
|
+
%ol
|
7
|
+
- any = false
|
8
|
+
- @results.each do |r|
|
9
|
+
- any = true
|
10
|
+
%li
|
11
|
+
.title= link_to (r._highlight.nil? || r._highlight['name'].nil?) ? r.name : r._highlight['name'].join(' ... ').html_safe, url_for(r)
|
12
|
+
.text
|
13
|
+
= raw (r._highlight.nil? || r._highlight['content'].nil?) ? (r.content.blank? ? '' : SmartExcerpt.truncate(r.content)) : r._highlight['content'].join(' ... ')
|
14
|
+
%span.more= link_to '', url_for(r)
|
15
|
+
|
16
|
+
- unless any
|
17
|
+
.rs-search-no-results К сожалению, ничего не найдено
|
18
|
+
|
19
|
+
= paginate @results if any
|
@@ -0,0 +1,6 @@
|
|
1
|
+
- unless !obj.respond_to?(:keywords) || obj.keywords.blank?
|
2
|
+
%meta{name: "keywords", content: obj.keywords}/
|
3
|
+
- unless !obj.respond_to?(:description) || obj.description.blank?
|
4
|
+
%meta{name: "description", content: obj.description}/
|
5
|
+
- unless !obj.respond_to?(:robots) || obj.robots.blank?
|
6
|
+
%meta{name: "robots", content: obj.robots}/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
- unless obj.nil?
|
2
|
+
.text_content
|
3
|
+
- unless obj.h1.blank?
|
4
|
+
%h1= obj.h1
|
5
|
+
- if obj.content.blank?
|
6
|
+
= raw @seo_page.page_content unless @seo_page.nil?
|
7
|
+
= render 'shared/admin_link', obj: @seo_page
|
8
|
+
- else
|
9
|
+
= raw obj.content
|
10
|
+
= render 'shared/admin_link', obj: obj
|
11
|
+
|
12
|
+
- content_for :meta do
|
13
|
+
= render 'shared/meta', obj: obj
|
14
|
+
= render 'shared/og', title: obj.get_og_title, image: obj.og_image
|
@@ -0,0 +1,17 @@
|
|
1
|
+
en:
|
2
|
+
rs:
|
3
|
+
cms: "CMS"
|
4
|
+
menu: "Menu"
|
5
|
+
settings: 'Settings'
|
6
|
+
news: 'News'
|
7
|
+
with_final_slash: "should begin with a slash"
|
8
|
+
page_url_regex: "Regular expression to check if page is current"
|
9
|
+
final_in_menu: "This link is also displayed in menu"
|
10
|
+
no_contact_info: "Please enter your phone or email so we could contact you."
|
11
|
+
map: 'Map'
|
12
|
+
edit: Edit
|
13
|
+
m:
|
14
|
+
enabled: 'added to menu "%{menu}"'
|
15
|
+
disabled: 'deleted from menu "%{menu}"'
|
16
|
+
error: "Error: %{err}"
|
17
|
+
no_id: "No ID"
|
@@ -0,0 +1,65 @@
|
|
1
|
+
ru:
|
2
|
+
devise:
|
3
|
+
confirmations:
|
4
|
+
confirmed: Ваша учётная запись подтверждена. Теперь вы вошли в систему.
|
5
|
+
send_instructions: В течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи.
|
6
|
+
send_paranoid_instructions: Если ваш адрес e-mail есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи.
|
7
|
+
failure:
|
8
|
+
already_authenticated: Вы уже вошли в систему.
|
9
|
+
inactive: Ваша учётная запись ещё не активирована.
|
10
|
+
invalid: Неверный адрес e-mail или пароль.
|
11
|
+
invalid_token: Неверный ключ аутентификации.
|
12
|
+
locked: Ваша учётная запись заблокирована.
|
13
|
+
not_found_in_database:
|
14
|
+
timeout: Ваш сеанс закончился. Пожалуйста, войдите в систему снова.
|
15
|
+
unauthenticated: Вам необходимо войти в систему или зарегистрироваться.
|
16
|
+
unconfirmed: Вы должны подтвердить вашу учётную запись.
|
17
|
+
mailer:
|
18
|
+
confirmation_instructions:
|
19
|
+
subject: Инструкции по подтверждению учётной записи
|
20
|
+
reset_password_instructions:
|
21
|
+
subject: Инструкции по восстановлению пароля
|
22
|
+
unlock_instructions:
|
23
|
+
subject: Инструкции по разблокировке учётной записи
|
24
|
+
omniauth_callbacks:
|
25
|
+
failure: Вы не можете войти в систему с учётной записью из %{kind}, т.к. "%{reason}".
|
26
|
+
success: Вход в систему выполнен с учётной записью из %{kind}.
|
27
|
+
passwords:
|
28
|
+
no_token: Доступ к этой странице возможен только по ссылке из письма о восстановлении пароля. Если Вы пришли по такой ссылке, пожалуйста убедитесь что Вы скопировали всю ссылку целиком.
|
29
|
+
send_instructions: В течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля.
|
30
|
+
send_paranoid_instructions: Если ваш адрес e-mail есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля.
|
31
|
+
updated: Ваш пароль изменён. Теперь вы вошли в систему.
|
32
|
+
updated_not_active: Ваш пароль изменен.
|
33
|
+
registrations:
|
34
|
+
destroyed: До свидания! Ваша учётная запись удалена. Надеемся снова увидеть вас.
|
35
|
+
signed_up: Добро пожаловать! Вы успешно зарегистрировались.
|
36
|
+
signed_up_but_inactive: Вы успешно зарегистрированы. Однако, вы не можете войти в систему, потому что ваша учетная запись не активирована.
|
37
|
+
signed_up_but_locked: Вы успешно зарегистрированы. Однако, вы не можете войти в систему, потому что ваша учетная запись заблокирована.
|
38
|
+
signed_up_but_unconfirmed: Письмо со ссылкой для подтверждения было отправлено на ваш e-mail. Пожалуйста, перейдите по ссылке, чтобы подтвердить вашу учетную запись.
|
39
|
+
update_needs_confirmation: Вы успешно обновили данные вашей учетной записи, но нам нужно проверить ваш новый адрес e-mail. Пожалуйста, проверьте ваш почтовый ящик и перейдите по ссылке, чтобы закончить процедуру проверки вашего нового адреса e-mail.
|
40
|
+
updated: Ваша учётная запись изменена.
|
41
|
+
sessions:
|
42
|
+
signed_in: Вход в систему выполнен.
|
43
|
+
signed_out: Выход из системы выполнен.
|
44
|
+
unlocks:
|
45
|
+
send_instructions: В течение нескольких минут вы получите письмо с инструкциями по разблокировке вашей учётной записи.
|
46
|
+
send_paranoid_instructions: Если ваша учётная запись существует, то в течение нескольких минут вы получите письмо с инструкциями по её разблокировке.
|
47
|
+
unlocked: Ваша учётная запись разблокирована. Теперь вы можете войти в систему.
|
48
|
+
failure:
|
49
|
+
user:
|
50
|
+
not_found_in_database: Пользователь не найден в базе
|
51
|
+
invalid: Неверный пароль
|
52
|
+
unauthenticated: Необходимо авторизоваться
|
53
|
+
unconfirmed: 'Необходимо подтвердить адрес электронной почты'
|
54
|
+
errors:
|
55
|
+
messages:
|
56
|
+
already_confirmed: уже подтверждена. Пожалуйста, попробуйте войти в систему
|
57
|
+
confirmation_period_expired:
|
58
|
+
expired: устарела. Пожалуйста, запросите новую
|
59
|
+
not_found: не найдена
|
60
|
+
not_locked: не заблокирована
|
61
|
+
not_saved:
|
62
|
+
few: ! '%{resource}: сохранение не удалось из-за %{count} ошибок'
|
63
|
+
many: ! '%{resource}: сохранение не удалось из-за %{count} ошибок'
|
64
|
+
one: ! '%{resource}: сохранение не удалось из-за %{count} ошибки'
|
65
|
+
other: ! '%{resource}: сохранение не удалось из-за %{count} ошибки'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ru:
|
2
|
+
views:
|
3
|
+
pagination:
|
4
|
+
first: "« Начало"
|
5
|
+
last: "Конец »"
|
6
|
+
previous: "‹ Предыдущая"
|
7
|
+
next: "Следующая ›"
|
8
|
+
truncate: "…"
|
9
|
+
helpers:
|
10
|
+
page_entries_info:
|
11
|
+
one_page:
|
12
|
+
display_entries:
|
13
|
+
zero: "%{entry_name} не найдены"
|
14
|
+
one: "Показано <b>1</b> %{entry_name}"
|
15
|
+
other: "Показаны <b>все %{count}</b> %{entry_name}"
|
16
|
+
more_pages:
|
17
|
+
display_entries: "Показаны %{entry_name} <b>%{first} - %{last}</b> из <b>%{total}</b>"
|
@@ -0,0 +1,78 @@
|
|
1
|
+
ru:
|
2
|
+
attributes:
|
3
|
+
user: Пользователь
|
4
|
+
name: Название
|
5
|
+
category: Раздел
|
6
|
+
file: Файл
|
7
|
+
short: Короткое описание
|
8
|
+
text: Текст
|
9
|
+
desc: Описание
|
10
|
+
image: Картинка
|
11
|
+
href: Ссылка
|
12
|
+
enabled: Включено
|
13
|
+
slug: URL код
|
14
|
+
text_slug: URL код
|
15
|
+
c_at: Создано
|
16
|
+
u_at: Обновлено
|
17
|
+
id: ID
|
18
|
+
content: Содержимое
|
19
|
+
time: Время
|
20
|
+
excerpt: Превью
|
21
|
+
sort: Сортировка
|
22
|
+
link: Ссылка
|
23
|
+
url: URL
|
24
|
+
address: Адрес
|
25
|
+
map_address: Адрес для карты
|
26
|
+
map_hint: Подсказка для карты
|
27
|
+
coordinates: Координаты из геокодирования
|
28
|
+
lat: Широта (вручную)
|
29
|
+
lon: Долгота (вручную)
|
30
|
+
description: SEO Description
|
31
|
+
email: Email
|
32
|
+
keywords: SEO Keywords
|
33
|
+
modifier_id: Кто правил
|
34
|
+
og_title: Og title
|
35
|
+
robots: Robots
|
36
|
+
title: Title
|
37
|
+
version: Version
|
38
|
+
|
39
|
+
mongoid:
|
40
|
+
models:
|
41
|
+
user: Пользователь
|
42
|
+
menu: Меню
|
43
|
+
page: Страница
|
44
|
+
contact_message: Сообщение
|
45
|
+
news: Новость
|
46
|
+
|
47
|
+
attributes:
|
48
|
+
user:
|
49
|
+
email: E-mail
|
50
|
+
old_password: Текущий пароль
|
51
|
+
password: Пароль
|
52
|
+
password_confirmation: Подтвердите пароль
|
53
|
+
remember_me: Запомнить
|
54
|
+
c_at: Создан
|
55
|
+
current_sign_in_ip: Текущий IP
|
56
|
+
last_sign_in_ip: Прошлый IP
|
57
|
+
first_name: Имя
|
58
|
+
last_name: Фамилия
|
59
|
+
phone: Телефон
|
60
|
+
|
61
|
+
page:
|
62
|
+
fullpath: URL
|
63
|
+
regexp: Подсветка меню
|
64
|
+
redirect: Редирект
|
65
|
+
image: Картинка
|
66
|
+
hidden: Скрытая
|
67
|
+
menus: Меню
|
68
|
+
contact_message:
|
69
|
+
name: Ваше имя
|
70
|
+
email: Ваш е-мейл
|
71
|
+
phone: Ваш телефон
|
72
|
+
content: Ваше сообщение
|
73
|
+
|
74
|
+
activemodel:
|
75
|
+
errors:
|
76
|
+
messages:
|
77
|
+
invalid_email_address: Неверный e-mail
|
78
|
+
|