diff --git a/.gitignore b/.gitignore index 2f761fe..98f38d2 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ coverage config/settings.local.yml config/settings/*.local.yml config/environments/*.local.yml +/.ruby-gemset +/.idea/* diff --git a/.ruby-version b/.ruby-version index 03463f3..e391e18 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-3.3.0 +ruby-3.3.6 diff --git a/Gemfile b/Gemfile index fc76bca..e7b53e0 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,9 @@ gem 'activerecord-import' gem 'sprockets-rails' gem 'slim-rails' +# Serializers +gem 'alba' + # Распаковка архивов gem 'rubyzip', require: 'zip' diff --git a/Gemfile.lock b/Gemfile.lock index d66b198..ce0b383 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -95,6 +95,8 @@ GEM uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) + alba (3.5.0) + ostruct (~> 0.6) arbre (1.7.0) activesupport (>= 3.0.0) ruby2_keywords (>= 0.0.2) @@ -448,6 +450,7 @@ DEPENDENCIES activeadmin activeadmin_addons activerecord-import + alba bundler-audit capybara config diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0d95db2..99ac083 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,5 @@ class ApplicationController < ActionController::Base + include Pagination # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. allow_browser versions: :modern end diff --git a/app/controllers/books_controller.rb b/app/controllers/books_controller.rb new file mode 100644 index 0000000..3607d3c --- /dev/null +++ b/app/controllers/books_controller.rb @@ -0,0 +1,6 @@ +class BooksController < ApplicationController + def index + books = paginate(Book.all) + render json: BookSerializer.new(books) + end +end diff --git a/app/controllers/concerns/pagination.rb b/app/controllers/concerns/pagination.rb new file mode 100644 index 0000000..cdc92b8 --- /dev/null +++ b/app/controllers/concerns/pagination.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Методы фильтрации сортировки и паджинации +module Pagination + extend ActiveSupport::Concern + # DEFAULT_LIMIT = Settings.app.items_per_page || 100 + + def paginate(items) + curr_page = params[:page] || 1 + limit = params[:per_page] || Settings.app.items_per_page || 100 + items.page(curr_page).per(limit) + end +end diff --git a/app/serializers/book_serializer.rb b/app/serializers/book_serializer.rb new file mode 100644 index 0000000..5841a37 --- /dev/null +++ b/app/serializers/book_serializer.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class BookSerializer + include Alba::Resource + root_key! + + attributes :id, :title +end diff --git a/config/database.yml b/config/database.yml index 48f30ee..1d3b752 100644 --- a/config/database.yml +++ b/config/database.yml @@ -5,10 +5,10 @@ default: &default prepared_statements: false postgre: &postgre - host: <%= ENV.fetch('POSTGRES_HOST', 'localhost') %> + host: <%= ENV.fetch('POSTGRES_HOST', '127.0.0.1') %> port: <%= ENV.fetch('POSTGRES_PORT', '5432') %> - username: <%= ENV.fetch('POSTGRES_USER') { 'igorsimdyanov' } %> - password: <%= ENV.fetch('POSTGRES_PASSWORD') { '' } %> + username: <%= ENV.fetch('POSTGRES_USER') { 'admin' } %> + password: <%= ENV.fetch('POSTGRES_PASSWORD') { 'admin' } %> development: <<: *default @@ -17,6 +17,7 @@ development: test: <<: *default + <<: *postgre database: library_test production: diff --git a/config/routes.rb b/config/routes.rb index ae608d2..91427a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -24,6 +24,9 @@ # Can be used by load balancers and uptime monitors to verify that the app is live. get 'up' => 'rails/health#show', as: :rails_health_check + get "books/(:page)" => 'books#index', page: /\d+/ + # resources :books, only: :index - Я бы предпочел маршруты строить ближе к REST, а номер страницы передавать в query параметрах, например /books?page=2&per_page=100 + # Render dynamic PWA files from app/views/pwa/* get 'service-worker' => 'rails/pwa#service_worker', as: :pwa_service_worker get 'manifest' => 'rails/pwa#manifest', as: :pwa_manifest diff --git a/docs/layers.pulm b/docs/layers.pulm new file mode 100644 index 0000000..40b5cb5 --- /dev/null +++ b/docs/layers.pulm @@ -0,0 +1,7 @@ +@startuml +Router -down->[use] Controller +Controller -down->[use] Command +Controller -down->[use] Model +Command -down->[use] Model +Controller -down->[use] Serializer +@enduml \ No newline at end of file diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f025175..145964a 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -64,4 +64,5 @@ # config.include Devise::Test::ControllerHelpers, type: :request config.include LoaderHelpers config.include LoginHelpers, type: :feature + config.include RequestHelper, type: :request end diff --git a/spec/requests/books_spec.rb b/spec/requests/books_spec.rb new file mode 100644 index 0000000..465e5af --- /dev/null +++ b/spec/requests/books_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe BooksController, type: :request do + let(:language) { create(:language) } + let(:folder) { create(:folder) } + let(:per_page) { 25 } + let!(:books) { create_list(:book, 30, language: language, folder: folder) } + + before do + allow(Settings.app).to receive(:items_per_page).and_return(per_page) + end + + describe "GET /index" do + it "returns http success" do + get "/books/2" + expect(json[:books].size).to eq(5) + end + + it "returns http success" do + get "/books" + expect(json[:books].size).to eq(25) + end + end +end diff --git a/spec/support/request_helper.rb b/spec/support/request_helper.rb new file mode 100644 index 0000000..b213e96 --- /dev/null +++ b/spec/support/request_helper.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module RequestHelper + def json + JSON.parse response.body, symbolize_names: true + end +end