diff --git a/Gemfile b/Gemfile index 716a9ba..9d6dda9 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,7 @@ gem "jbuilder" gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] gem 'slim-rails' gem "jsbundling-rails" +gem "kaminari" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem diff --git a/Gemfile.lock b/Gemfile.lock index 8aaae9a..0c7279c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -115,6 +115,18 @@ GEM activesupport (>= 5.0.0) jsbundling-rails (1.3.1) railties (>= 6.0.0) + kaminari (1.2.2) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.2) + kaminari-activerecord (= 1.2.2) + kaminari-core (= 1.2.2) + kaminari-actionview (1.2.2) + actionview + kaminari-core (= 1.2.2) + kaminari-activerecord (1.2.2) + activerecord + kaminari-core (= 1.2.2) + kaminari-core (1.2.2) logger (1.6.1) loofah (2.23.1) crass (~> 1.0.2) @@ -290,6 +302,7 @@ DEPENDENCIES faker jbuilder jsbundling-rails + kaminari pry-rails puma (~> 5.0) rails (~> 7.0.1) diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index 6559b9e..4214d8b 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -1,7 +1,8 @@ class PeopleController < ApplicationController - def index - @people = Person.all + page = params[:page].to_i + page = 1 if page == 0 + @people = People::List.new(page: page).execute end def new @@ -9,18 +10,17 @@ def new end def create - if Person.create(person_attributes) + @person = Person.new(person_attributes) + if @person.save redirect_to people_path, notice: 'Successfully created entry' else - render :create, alert: 'Unsuccessfully created entry' + render :new, alert: 'Unsuccessfully created entry', status: :unprocessable_entity end end private def person_attributes - params.require(:person).permit(:name, :email, :phone) + params.require(:person).permit(:name, :email, :phone_number) end - end - diff --git a/app/models/people/list.rb b/app/models/people/list.rb new file mode 100644 index 0000000..53fba1a --- /dev/null +++ b/app/models/people/list.rb @@ -0,0 +1,10 @@ +class People::List + private attr_accessor :page + def initialize(page:) + self.page = page + end + + def execute + Person.order(:id).page(page).per(10) + end +end diff --git a/app/models/person.rb b/app/models/person.rb index f935e46..cea424c 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -14,4 +14,8 @@ class Person < ApplicationRecord belongs_to :company, optional: true + + validates :name, presence: true + validates :phone_number, presence: true + validates :email, presence: true end diff --git a/app/views/kaminari/_first_page.html.slim b/app/views/kaminari/_first_page.html.slim new file mode 100644 index 0000000..cc5a1cc --- /dev/null +++ b/app/views/kaminari/_first_page.html.slim @@ -0,0 +1,2 @@ +li.page-item + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' diff --git a/app/views/kaminari/_gap.html.slim b/app/views/kaminari/_gap.html.slim new file mode 100644 index 0000000..ecaec7e --- /dev/null +++ b/app/views/kaminari/_gap.html.slim @@ -0,0 +1,2 @@ +li.page-item.disabled + = link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' diff --git a/app/views/kaminari/_last_page.html.slim b/app/views/kaminari/_last_page.html.slim new file mode 100644 index 0000000..710f1eb --- /dev/null +++ b/app/views/kaminari/_last_page.html.slim @@ -0,0 +1,2 @@ +li.page-item + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, remote: remote, class: 'page-link' diff --git a/app/views/kaminari/_next_page.html.slim b/app/views/kaminari/_next_page.html.slim new file mode 100644 index 0000000..5adc455 --- /dev/null +++ b/app/views/kaminari/_next_page.html.slim @@ -0,0 +1,2 @@ +li.page-item + = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link' diff --git a/app/views/kaminari/_page.html.slim b/app/views/kaminari/_page.html.slim new file mode 100644 index 0000000..80b5e2f --- /dev/null +++ b/app/views/kaminari/_page.html.slim @@ -0,0 +1,6 @@ +- if page.current? + li.page-item.active + = content_tag :a, page, data: { remote: remote }, rel: page.rel, class: 'page-link' +- else + li.page-item + = link_to page, url, remote: remote, rel: page.rel, class: 'page-link' diff --git a/app/views/kaminari/_paginator.html.slim b/app/views/kaminari/_paginator.html.slim new file mode 100644 index 0000000..5dcf566 --- /dev/null +++ b/app/views/kaminari/_paginator.html.slim @@ -0,0 +1,12 @@ += paginator.render do + nav + ul.pagination + == first_page_tag unless current_page.first? + == prev_page_tag unless current_page.first? + - each_page do |page| + - if page.left_outer? || page.right_outer? || page.inside_window? + == page_tag page + - elsif !page.was_truncated? + == gap_tag + == next_page_tag unless current_page.last? + == last_page_tag unless current_page.last? diff --git a/app/views/kaminari/_prev_page.html.slim b/app/views/kaminari/_prev_page.html.slim new file mode 100644 index 0000000..83f33ee --- /dev/null +++ b/app/views/kaminari/_prev_page.html.slim @@ -0,0 +1,2 @@ +li.page-item + = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link' diff --git a/app/views/people/index.html.slim b/app/views/people/index.html.slim index ddbf52f..8a9bce0 100644 --- a/app/views/people/index.html.slim +++ b/app/views/people/index.html.slim @@ -13,9 +13,10 @@ table.table tr th[scope="row"]= person&.id td= person.try(:name) - td= person.try(:phone) + td= person.try(:phone_number) td= person.try(:email) td= person.try(:company).try(:name) += paginate @people diff --git a/config/initializers/kaminari_config.rb b/config/initializers/kaminari_config.rb new file mode 100644 index 0000000..4ba6ee3 --- /dev/null +++ b/config/initializers/kaminari_config.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +Kaminari.configure do |config| + # config.default_per_page = 25 + # config.max_per_page = nil + # config.window = 4 + # config.outer_window = 0 + # config.left = 0 + # config.right = 0 + # config.page_method_name = :page + # config.param_name = :page + # config.max_pages = nil + # config.params_on_first_page = false +end diff --git a/spec/controllers/people_controller_spec.rb b/spec/controllers/people_controller_spec.rb index 82220e8..00a4536 100644 --- a/spec/controllers/people_controller_spec.rb +++ b/spec/controllers/people_controller_spec.rb @@ -22,5 +22,9 @@ it 'has status found' do expect(post :create, params: { person: { name: 'foo', phone_number: '123', email: 'foo' } }).to have_http_status(:found) end + + it 'doesn\'t create a user when is missing phone_number' do + expect(post :create, params: { person: { name: 'foo', email: 'foo' } }).to have_http_status(:unprocessable_entity) + end end end diff --git a/spec/factories/companies.rb b/spec/factories/companies.rb new file mode 100644 index 0000000..0752e24 --- /dev/null +++ b/spec/factories/companies.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :company do + name { "Company default" } + end +end diff --git a/spec/factories/people.rb b/spec/factories/people.rb new file mode 100644 index 0000000..4683afa --- /dev/null +++ b/spec/factories/people.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :person do + name { "John Doe" } + email { "john@doe.com" } + phone_number { "9770607060" } + end +end diff --git a/spec/features/people/index_spec.rb b/spec/features/people/index_spec.rb index d9936a9..c998277 100644 --- a/spec/features/people/index_spec.rb +++ b/spec/features/people/index_spec.rb @@ -1,8 +1,9 @@ require 'rails_helper' RSpec.describe 'Listing people', type: :feature do - before do - Person.create( + before do + FactoryBot.create( + :person, name: 'Foo Bar', phone_number: 'Biz', email: 'Baz' @@ -18,10 +19,23 @@ end end + scenario 'with more users than allowed in view' do + people_list = FactoryBot.create_list(:person, 11) + last_record = people_list.last + last_record.update(name: 'Jane Doe', email: 'jane@doe.com') + + visit people_path + + expect(page).to_not have_content('Jane Doe') + + click_on 'Next' + + expect(page).to have_content('Jane Doe') + end + scenario 'New person', type: :feature do visit new_person_path expect(page).to have_field :person_name end - end diff --git a/spec/views/people/index.html.slim_spec.rb b/spec/views/people/index.html.slim_spec.rb index 7e2d362..a3adb10 100644 --- a/spec/views/people/index.html.slim_spec.rb +++ b/spec/views/people/index.html.slim_spec.rb @@ -1,5 +1,17 @@ require "rails_helper" describe "people/index.html.slim" do - it "Displays the users" + let(:company) { FactoryBot.create(:company, name: "Default Company") } + let!(:first_person) { FactoryBot.create(:person, phone_number: "Foo", company: company) } + let!(:second_person) { FactoryBot.create(:person, name: "Jane Doe", email: "jane@doe.com.br", phone_number: "Bar", company: company) } + it "Displays the users" do + assign(:people, People::List.new(page: 1).execute) + render + + expect(rendered).to match(/John/) # name (John) + expect(rendered).to match(/Foo/) # phone number + expect(rendered).to match(/Jane/) # name (Jane) + expect(rendered).to match(/Bar/) # phone number + expect(rendered).to match(/Default Company/) # company name + end end