diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..88aa06a --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,40 @@ +version: 2.0 + +jobs: + "ruby-3.0.0": + docker: + - image: circleci/ruby:3.0.0 + environment: + BUNDLE_JOBS: 3 + BUNDLE_RETRY: 3 + BUNDLE_PATH: vendor/bundle + steps: + - checkout + - restore_cache: + keys: + - v1-bundle-{{ .Branch }}-{{ checksum "invitation.gemspec" }} + - v1-bundle-{{ .Branch }} + - run: + name: Upgrade Bundler + command: gem install --no-doc bundler -v "$(grep bundler *.gemspec | awk '{print $NF}' | tr -d \' )" + - run: + name: Bundle Install + command: bundle install + - save_cache: + key: v1-bundle-{{ .Branch }}-{{ checksum "invitation.gemspec" }} + paths: + - vendor/bundle + - run: + name: Run rspec in parallel + command: | + bundle exec rspec --profile 10 \ + --out test_results/rspec.xml \ + --format progress + - store_test_results: + path: test_results + +workflows: + version: 2 + test: + jobs: + - "ruby-3.0.0" diff --git a/.gitignore b/.gitignore index 8726991..e12ab61 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ spec/dummy/tmp/ spec/dummy/.sass-cache /.idea/ *emfile.lock +.byebug_history +``` diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 0bee604..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.3.3 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..2c0c270 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.0.0 diff --git a/README.md b/README.md index ed0b5e8..5a182f4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ Please use [GitHub Issues] to report bugs. You can contact me directly on twitte [![Gem Version](https://badge.fury.io/rb/invitation.svg)](https://badge.fury.io/rb/invitation) ![Build status](https://travis-ci.org/tomichj/invitation.svg?branch=master) ![Code Climate](https://codeclimate.com/github/tomichj/invitation/badges/gpa.svg) - ## Overview Allow users to invite others to join an organization or resource. Plenty of gems can issue a 'system-wide' invitation, @@ -18,25 +17,23 @@ but few offer 'scoped' invitations, giving an invited user access to a particula Invitations are issued via email. You can invite users new to join the system while giving them permissions to a resource, or invite existing users by giving them access to a new resource. -* a user can invite someone to join an invitable by providing an email address to invite -* if the user already exists, that user is granted access to the invitable, and a notification email is sent -* if the user does not exist, sends an email with a link to sign up. When the new user signs up, -they are added to the invitable resource/organization. -* the invite grants the invited user access to ONLY the invitable organization they were invited to. - +- a user can invite someone to join an invitable by providing an email address to invite +- if the user already exists, that user is granted access to the invitable, and a notification email is sent +- if the user does not exist, sends an email with a link to sign up. When the new user signs up, + they are added to the invitable resource/organization. +- the invite grants the invited user access to ONLY the invitable organization they were invited to. ## Prerequisites -* An authentication system with a User model and current_user helper, e.g. https://github.com/tomichj/authenticate -* Your user model must include an :email attribute. -* Additional model classes that are resources or organizations you wish to invite users to join, usually with a -many-to-many relationship to your user model. -* You probably also want an authorization system to restrict who can issue invitations to particular resources +- An authentication system with a User model and current_user helper, e.g. https://github.com/tomichj/authenticate +- Your user model must include an :email attribute. +- Additional model classes that are resources or organizations you wish to invite users to join, usually with a + many-to-many relationship to your user model. +- You probably also want an authorization system to restrict who can issue invitations to particular resources -A example user-to-organization system you might be familiar with: Basecamp's concepts of accounts and +A example user-to-organization system you might be familiar with: Basecamp's concepts of accounts and projects (invitables) and users. - ## Install To get started, add Invitation to your `Gemfile` and run `bundle install` to install it: @@ -51,14 +48,13 @@ Then run the invitation install generator: rails generate invitation:install ``` -If your user model is not User, you can optionally specify one: `rails generate invitation:install --model Profile`. +If your user model is not User, you can optionally specify one: `rails generate invitation:install --model Profile`. The install generator does the following: -* Add an initializer at `config/initializers/invitation.rb`, see [Configure](#configure) below. -* Insert `include Invitation::User` into your `User` model. -* Create a migration for the Invite class. - +- Add an initializer at `config/initializers/invitation.rb`, see [Configure](#configure) below. +- Insert `include Invitation::User` into your `User` model. +- Create a migration for the Invite class. Then run the migration that Invitation just generated. @@ -66,7 +62,6 @@ Then run the migration that Invitation just generated. rake db:migrate ``` - ## Configure Override any of these defaults in your application `config/initializers/invitation.rb`. @@ -74,7 +69,7 @@ Override any of these defaults in your application `config/initializers/invitati ```ruby Invitation.configure do |config| config.user_model = '::User' - config.user_registration_url = ->(params) { Rails.application.routes.url_helpers.sign_up_url(params) } + config.user_registration_url = ->(params) { Rails.application.routes.url_helpers.sign_up_url(params) } config.mailer_sender = 'reply@example.com' config.routes = true config.case_sensitive_email = true @@ -83,16 +78,16 @@ end Configuration parameters are described in detail here: [configuration] - ### Invitable You'll need to configure one or more model classes as `invitables`. Invitables are resources or organizations that can be joined with an invite. -An `invitable` must have some sort of name for Invitation to use in views and mailers. An invitable needs to +An `invitable` must have some sort of name for Invitation to use in views and mailers. An invitable needs to call a class method, `invitable`, with one of the following options: -* `named: "String"` -* `named_by: :some_method_name`. + +- `named: "String"` +- `named_by: :some_method_name`. Example: a Company model that users can be invited to join. The companies are identified in invitation emails by their `name` attribute: @@ -103,20 +98,21 @@ class Company < ActiveRecord::Base end ``` - ### User Registration Controller Your user registration controller must `include Invitation::UserRegistration`. You'll want to invoke `set_invite_token` before you execute your `new` action, and `process_invite_token` after your `create` action. If you're using [Authenticate](https://github.com/tomichj/authenticate), for example: + ```ruby class UsersController < Authenticate::UsersController include Invitation::UserRegistration before_action :set_invite_token, only: [:new] after_action :process_invite_token, only: [:create] end -``` +``` + To pass the invite token on signup, add `invite_token` as a hidden field in your signup form. ## Usage @@ -125,26 +121,26 @@ Invitation adds routes to create invitations (GET new_invite and POST invites). Invitation and set up an invitable, add a link to new_invite, specifying the the invitable id and type in the link: ```erb - <%= link_to 'invite a friend', + <%= link_to 'invite a friend', new_invite_path(invite: { invitable_id: account.id, invitable_type: 'Account' } ) %> ``` -Invitation includes a simple `invitations#new` view which accepts an email address for a user to invite. +Invitation includes a simple `invitations#new` view which accepts an email address for a user to invite. When the form is submitted, [invites#create](app/controllers/invitation/invites_controller.rb) will create an [invite](app/models/invite.rb) to track the invitation. An email is then sent: -* a new user is emailed a link to your user registration page as set in [configuration], with a secure -invitation link that will be used to 'claim' the invitation when the new user registers - -* an existing user is emailed a notification to tell them that they've been added to the resource +- a new user is emailed a link to your user registration page as set in [configuration], with a secure + invitation link that will be used to 'claim' the invitation when the new user registers +- an existing user is emailed a notification to tell them that they've been added to the resource ### JSON Invitation You can send a JSON request to [invites#create](app/controllers/invitation/invites_controller.rb). -* request: +- request: + ```javascript invite: { @@ -165,37 +161,40 @@ invite: } ``` -* response: +- response: + ```javascript { - "id": Number, - "email": String, - "sender_id": Number, - "recipient_id": Number (optional), - "invitable_id": Number, - "invitable_type": String, + "id": Number, + "email": String, + "sender_id": Number, + "recipient_id": Number (optional), + "invitable_id": Number, + "invitable_type": String, } ``` or, with multiple emails requested, an array of responses: ```javascript -[{ - "id": Number, - "email": String, - "sender_id": Number, - "recipient_id": Number (optional), - "invitable_id": Number, - "invitable_type": String, -}, -{ - "id": Number, - "email": String, - "sender_id": Number, - "recipient_id": Number (optional), - "invitable_id": Number, - "invitable_type": String, -}] +[ + { + id: Number, + email: String, + sender_id: Number, + recipient_id: Number(optional), + invitable_id: Number, + invitable_type: String, + }, + { + id: Number, + email: String, + sender_id: Number, + recipient_id: Number(optional), + invitable_id: Number, + invitable_type: String, + }, +]; ``` ## Security @@ -207,8 +206,9 @@ Most implementations will require extending the `InvitationsController`. [See be about extending InvitationController. A common use case: -* every invitable resource has authorization requirements exposed via a method, we'll call it `can_invite?(user)` -* the current user must be authorized before issuing invitations + +- every invitable resource has authorization requirements exposed via a method, we'll call it `can_invite?(user)` +- the current user must be authorized before issuing invitations To implement: extend `InvitesController` and add a before_action to authorize access to the resource or resources. A real implementation would probably do something more than just `raise 'unauthorized'`. @@ -231,10 +231,8 @@ class InvitesController < Invitation::InvitesController end ``` - ## Overriding Invitation - ### Views You can quickly get started with a rails application using the built-in views. See [app/views](/app/views) for @@ -247,7 +245,6 @@ You can use the Invitation view generator to copy the default views and translat $ rails generate invitation:views ``` - ### Routes Invitation adds routes to your application. See [config/routes.rb](/config/routes.rb) for the default routes. @@ -271,7 +268,6 @@ will also switch off the routes by setting `config.routes = false` in your [conf $ rails generate invitation:routes ``` - ### Controllers You can customize the `invites_controller.rb` and the `invites_mailer.rb`. See [app/controllers](/app/controllers) @@ -279,7 +275,7 @@ for the controller, and [app/mailers](/app/mailers) for the mailer. To override `invites_controller.rb`, subclass the controller and update your routes to point to your implementation. -* subclass the controller: +- subclass the controller: ```ruby # app/controllers/invites_controller.rb @@ -292,12 +288,12 @@ class InvitesController < Invitation::InvitesController end ``` -* update your routes to use your new controller. +- update your routes to use your new controller. Start by dumping a copy of Invitation's routes to your `config/routes.rb`: ```sh -$ rails generate invitation:routes +$ rails generate invitation:routes ``` Now update `config/routes.rb`, changing the controller entry so it now points to your `invites` controller instead @@ -307,21 +303,20 @@ of `invitation/invites`: resources :invites, controller: 'invites', only: [:new, :create] ``` -You can also use the Invitation controller generator to copy the default controller and mailer into +You can also use the Invitation controller generator to copy the default controller and mailer into your application if you would prefer to more heavily modify the controller. ```sh $ rails generate invitation:controllers ``` - ### Layout Invitation uses your application's default layout. If you would like to change the layout Invitation uses when rendering views, you can either deploy copies of the controllers and customize them, or you can specify the layout in an initializer. This should be done in a to_prepare callback in `config/application.rb` because it's executed once in production and before each request in development. - + You can specify the layout per-controller: ```ruby @@ -330,7 +325,6 @@ config.to_prepare do end ``` - ### Translations All flash messages and email subject lines are stored in [i18n translations](http://guides.rubyonrails.org/i18n.html). @@ -338,39 +332,39 @@ Override them like any other i18n translation. See [config/locales/invitation.en.yml](/config/locales/invitation.en.yml) for the default messages. - ## Thanks This gem was inspired by and draws heavily from: -* https://gist.github.com/jlegosama/9026919 + +- https://gist.github.com/jlegosama/9026919 With additional inspiration from: -* https://github.com/scambra/devise_invitable + +- https://github.com/scambra/devise_invitable ## Contributors Many thanks to: -* [augustocbx](https://github.com/augustocbx) added pt-BR locale file and fixed an init bug -* [vincentwoo](https://github.com/vincentwoo/) raising the security bar, & bumping Invitation to rails 5.1 -* [conarro](https://github.com/conarro) added case_sensitive_email configuration option -* [itkin](https://github.com/itkin) bugfix, stringified configuration.user_model -* [thesubr00t](https://github.com/thesubr00t) made recipient association optional for rails 5+ +- [augustocbx](https://github.com/augustocbx) added pt-BR locale file and fixed an init bug +- [vincentwoo](https://github.com/vincentwoo/) raising the security bar, & bumping Invitation to rails 5.1 +- [conarro](https://github.com/conarro) added case_sensitive_email configuration option +- [itkin](https://github.com/itkin) bugfix, stringified configuration.user_model +- [thesubr00t](https://github.com/thesubr00t) made recipient association optional for rails 5+ ## Future changes -* accepted flag, so we can scope invites by accepted vs not yet accepted -* expiration date - invites expire, scope expired by not expired -* move all view text to locale -* issue many invitations at once? -* dynamic user name lookup? requires JS, CSS -* add JS support to invites#create +- accepted flag, so we can scope invites by accepted vs not yet accepted +- expiration date - invites expire, scope expired by not expired +- move all view text to locale +- issue many invitations at once? +- dynamic user name lookup? requires JS, CSS +- add JS support to invites#create ## License This project rocks and uses MIT-LICENSE. - [configuration]: lib/invitation/configuration.rb [CHANGELOG]: CHANGELOG.md [GitHub Issues]: https://github.com/tomichj/invitation/issues diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000..e694c75 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ + //= link_tree ../images + //= link_directory ../javascripts .js + //= link_directory ../stylesheets .css \ No newline at end of file diff --git a/app/controllers/invitation/invites_controller.rb b/app/controllers/invitation/invites_controller.rb index 32f6049..723f2b8 100644 --- a/app/controllers/invitation/invites_controller.rb +++ b/app/controllers/invitation/invites_controller.rb @@ -13,7 +13,7 @@ module Invitation # * override after_invite_existing_user or after_invite_new_user # class InvitesController < ApplicationController - + def new @invite = InviteForm.new(invite_params) render template: 'invites/new' @@ -24,12 +24,8 @@ def new # invite: { invitable_id, invitable_type, email or emails:[] } # def create - failures = [] invites = InviteForm.new(invite_params).build_invites(current_user) - ActiveRecord::Base.transaction do - invites.each { |invite| invite.save ? do_invite(invite) : failures << invite.email } - end - + failures = Invitation::InviteEmails.new(invites).send_invites logger.info "!!!!!!!!!!!!!!!!!!!!! INSIDE CREATE: current_user: #{current_user.inspect}" respond_to do |format| format.html do @@ -55,21 +51,6 @@ def create end end - private - - # Override this if you want to do something more complicated for existing users. - # For example, if you have a more complex permissions scheme than just a simple - # has_many relationship, enable it here. - def after_invite_existing_user(invite) - # Add the user to the invitable resource/organization - invite.invitable.add_invited_user(invite.recipient) - end - - # Override if you want to do something more complicated for new users. - # By default we don't do anything extra. - def after_invite_new_user(invite) - end - # After an invite is created, redirect the user here. # Default implementation doesn't return a url, just the invitable. def url_after_invite(invite) @@ -79,28 +60,5 @@ def url_after_invite(invite) def invite_params params[:invite] ? params.require(:invite).permit(:invitable_id, :invitable_type, :email, emails: []) : {} end - - # Invite user by sending email. - # Existing users are granted permissions via #after_invite_existing_user. - # New users are granted permissions via #after_invite_new_user, currently a null op. - def do_invite(invite) - if invite.existing_user? - deliver_email(InviteMailer.existing_user(invite)) - after_invite_existing_user(invite) - invite.save - else - deliver_email(InviteMailer.new_user(invite)) - after_invite_new_user(invite) - end - end - - # Use deliver_later from rails 4.2+ if available. - def deliver_email(mail) - if mail.respond_to?(:deliver_later) - mail.deliver_later - else - mail.deliver - end - end end end diff --git a/app/models/invite.rb b/app/models/invite.rb index 73ef069..28e3657 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -14,7 +14,7 @@ class Invite < ActiveRecord::Base end before_create :generate_token - before_save :set_email_case, on: :create + before_save :set_email_case, if: :new_record? before_save :check_recipient_existence validates :email, presence: true diff --git a/app/operations/invitation/invite_emails.rb b/app/operations/invitation/invite_emails.rb new file mode 100644 index 0000000..5030046 --- /dev/null +++ b/app/operations/invitation/invite_emails.rb @@ -0,0 +1,56 @@ +module Invitation + class InviteEmails + attr_reader :invites, :failures, :mailer + + def initialize(invites, opts = {}) + @invites = invites + @mailer = opts[:mailer] || InviteMailer + end + + def send_invites + @failures = [] + ActiveRecord::Base.transaction do + invites.each { |invite| invite.save ? do_invite(invite) : @failures << invite.email } + end + @failures + end + + # Invite user by sending email. + # Existing users are granted permissions via #after_invite_existing_user. + # New users are granted permissions via #after_invite_new_user, currently a null op. + def do_invite(invite) + if invite.existing_user? + deliver_email(mailer.existing_user(invite)) + after_invite_existing_user(invite) + invite.save + else + deliver_email(mailer.new_user(invite)) + after_invite_new_user(invite) + end + end + + # Use deliver_later from rails 4.2+ if available. + def deliver_email(mail) + if mail.respond_to?(:deliver_later) + mail.deliver_later + else + mail.deliver + end + end + + private + + # Override this if you want to do something more complicated for existing users. + # For example, if you have a more complex permissions scheme than just a simple + # has_many relationship, enable it here. + def after_invite_existing_user(invite) + # Add the user to the invitable resource/organization + invite.invitable.add_invited_user(invite.recipient) + end + + # Override if you want to do something more complicated for new users. + # By default we don't do anything extra. + def after_invite_new_user(invite) + end + end +end diff --git a/invitation.gemspec b/invitation.gemspec index 4780d14..959201a 100644 --- a/invitation.gemspec +++ b/invitation.gemspec @@ -1,5 +1,5 @@ require 'English' -$LOAD_PATH.push File.expand_path('../lib', __FILE__) +$LOAD_PATH.push File.expand_path('lib', __dir__) require 'invitation/version' require 'date' @@ -17,20 +17,21 @@ Gem::Specification.new do |s| s.files = Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.rdoc'] s.test_files = Dir['test/**/*'] - s.add_dependency 'rails', '>= 4.0', '< 5.2' + s.add_dependency 'rails', '~> 7.0.4.3', '< 8.0' + s.add_development_dependency 'appraisal' + s.add_development_dependency 'bundler', '~> 2.4', '>= 2.4.12' + s.add_development_dependency 'byebug' + s.add_development_dependency 'capybara' + s.add_development_dependency 'database_cleaner' s.add_development_dependency 'factory_girl', '~> 4.8' - s.add_development_dependency 'rspec-rails', '~> 3.5' - s.add_development_dependency 'rspec-mocks', '~> 3.5' s.add_development_dependency 'pry', '~> 0.10' - s.add_development_dependency 'sqlite3' + s.add_development_dependency 'rake' + s.add_development_dependency 'rspec-mocks' + s.add_development_dependency 'rspec-rails' s.add_development_dependency 'shoulda-matchers' - s.add_development_dependency 'capybara' - s.add_development_dependency 'database_cleaner' + s.add_development_dependency 'sqlite3' s.add_development_dependency 'timecop' - s.add_development_dependency 'appraisal' - s.add_development_dependency 'bundler' - s.add_development_dependency 'rake' s.required_ruby_version = Gem::Requirement.new('>= 2.0') end diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 0000000..e694c75 --- /dev/null +++ b/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,3 @@ + //= link_tree ../images + //= link_directory ../javascripts .js + //= link_directory ../stylesheets .css \ No newline at end of file diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index 04af407..3f0d39b 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -10,6 +10,7 @@ class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.load_defaults 7.0 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb index b55e214..5f0e0f8 100644 --- a/spec/dummy/config/environments/development.rb +++ b/spec/dummy/config/environments/development.rb @@ -35,7 +35,7 @@ # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true - + # config.assets.precompile = ["manifest.js"] # Raises error for missing translations # config.action_view.raise_on_missing_translations = true end diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb index 5c1b32e..a7b9d1f 100644 --- a/spec/dummy/config/environments/production.rb +++ b/spec/dummy/config/environments/production.rb @@ -34,6 +34,8 @@ # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. config.assets.digest = true + + # config.assets.precompile = ["manifest.js"] # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index 1e09eca..2ed8783 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -6,7 +6,8 @@ # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true - + # config.assets.precompile = ["manifest.js"] + # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb deleted file mode 100644 index 01ef3e6..0000000 --- a/spec/dummy/config/initializers/assets.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' - -# Add additional assets to the asset load path -# Rails.application.config.assets.paths << Emoji.images_path - -# Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. -# Rails.application.config.assets.precompile += %w( search.js ) diff --git a/spec/operations/invitation/invite_emails_spec.rb b/spec/operations/invitation/invite_emails_spec.rb new file mode 100644 index 0000000..2281929 --- /dev/null +++ b/spec/operations/invitation/invite_emails_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +RSpec.describe Invitation::InviteEmails do + describe 'custom mailer' do + let(:mail) { double('Mail') } + let(:test_mailer) { double('InviteMailer') } + + subject { described_class.new(invites, mailer: test_mailer).send_invites } + + let(:invites) { [create(:invite, :recipient_is_existing_user)] } + + it 'sends email through the given mailer' do + allow(mail).to receive(:deliver).once + expect(test_mailer).to receive(:existing_user).once.and_return(mail) + subject + end + end +end diff --git a/spec/requests/invite_one_user_spec.rb b/spec/requests/invite_one_user_spec.rb index dc50466..0b6a7ca 100644 --- a/spec/requests/invite_one_user_spec.rb +++ b/spec/requests/invite_one_user_spec.rb @@ -9,18 +9,18 @@ context 'invite a new user' do let(:email) { 'gug@gug.com' } - subject { + subject do do_post invites_path, - params: { invite: { invitable_id: @company.id, - invitable_type: @company.class.name, - email: email } }, - **json_headers() - } + params: { invite: { invitable_id: @company.id, + invitable_type: @company.class.name, + email: email } }, + **json_headers + end it 'returns json' do sign_in_with @user subject - expect(response.content_type).to eq('application/json') + expect(response.content_type).to eq('application/json; charset=utf-8') end it 'returns success' do @@ -45,7 +45,5 @@ expect(invite['invitable_id']).to eq @company.id expect(invite['invitable_type']).to eq @company.class.name end - end end - diff --git a/spec/requests/invite_two_users_spec.rb b/spec/requests/invite_two_users_spec.rb index b721e38..a2d1b38 100644 --- a/spec/requests/invite_two_users_spec.rb +++ b/spec/requests/invite_two_users_spec.rb @@ -12,16 +12,16 @@ let(:email2) { 'gug2@gug.com' } subject do do_post invites_path, - params: { invite: { invitable_id: @company.id, - invitable_type: @company.class.name, - emails: [email1, email2] } }, - **json_headers() + params: { invite: { invitable_id: @company.id, + invitable_type: @company.class.name, + emails: [email1, email2] } }, + **json_headers end it 'returns json' do sign_in_with @user subject - expect(response.content_type).to eq('application/json') + expect(response.content_type).to eq('application/json; charset=utf-8') end it 'responds with success' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2c1336a..fda0f1b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,12 +1,10 @@ $LOAD_PATH.unshift(File.dirname(__FILE__)) ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../dummy/config/environment.rb', __FILE__) +require File.expand_path('dummy/config/environment.rb', __dir__) # nasty hacky catch of environment data wiped out by tests run in rails 4 via appraisal -if ActiveRecord::VERSION::STRING >= '5.0' - system('bin/rails dummy:db:environment:set RAILS_ENV=test') -end +system('bin/rails dummy:db:environment:set RAILS_ENV=test') if ActiveRecord::VERSION::STRING >= '5.0' require 'rspec/rails' require 'shoulda-matchers' @@ -14,6 +12,7 @@ require 'capybara/rspec' require 'factory_girl' require 'timecop' +require 'byebug' Rails.backtrace_cleaner.remove_silencers! @@ -64,8 +63,9 @@ def mock_request(params = {}) # def do_post(path, *args) if Rails::VERSION::MAJOR >= 5 - post path, *args + # byebug + post path, **args.first else - post path, *(args.collect{|i| i.values}.flatten) + post path, *args.collect { |i| i.values }.flatten end end diff --git a/test_results/rspec.xml b/test_results/rspec.xml new file mode 100644 index 0000000..9fc3c3b --- /dev/null +++ b/test_results/rspec.xml @@ -0,0 +1,9 @@ + +Randomized with seed 6387 +................................................. + +Finished in 0.95816 seconds (files took 4.23 seconds to load) +49 examples, 0 failures + +Randomized with seed 6387 +