├── .coveralls.yml ├── .gitignore ├── .rspec ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── detectify.gemspec ├── lib ├── detectify.rb ├── detectify │ ├── config.rb │ ├── detector.rb │ ├── middleware.rb │ ├── query_builder │ │ ├── base.rb │ │ └── sql.rb │ ├── railtie.rb │ └── version.rb └── generators │ └── detectify │ ├── install_generator.rb │ └── templates │ └── detectify.rb └── spec ├── detectify ├── config_spec.rb ├── detectify_spec.rb ├── detector_spec.rb ├── middleware_spec.rb └── query_builder │ ├── base_spec.rb │ └── sql_spec.rb └── spec_helper.rb /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | 11 | .DS_Store 12 | 13 | .idea 14 | .rvmrc 15 | .ruby-gemset 16 | .ruby-version 17 | 18 | .byebug_history 19 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format Fuubar 2 | --color 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.2.2 5 | before_install: gem install bundler -v 1.12.5 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This code of conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at lukyanov.f.ua@gmail.com. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 45 | version 1.3.0, available at 46 | [http://contributor-covenant.org/version/1/3/0/][version] 47 | 48 | [homepage]: http://contributor-covenant.org 49 | [version]: http://contributor-covenant.org/version/1/3/0/ 50 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Lukyanov Fedor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Detectify 2 | [![Gem Version](https://badge.fury.io/rb/detectify.svg)](https://badge.fury.io/rb/detectify) 3 | [![Code Climate](https://codeclimate.com/github/rubygarage/detectify/badges/gpa.svg)](https://codeclimate.com/github/rubygarage/detectify) 4 | [![Coverage Status](https://coveralls.io/repos/github/rubygarage/detectify/badge.svg?branch=master)](https://coveralls.io/github/rubygarage/detectify?branch=master) 5 | [![Build Status](https://travis-ci.org/rubygarage/detectify.svg?branch=master)](https://travis-ci.org/rubygarage/detectify) 6 | 7 | Detectify provides a simple way to retrieve an ActiveRecord entity based on the domain/subdomain request information. 8 | 9 | It’s a Ruby gem, similar to Houser, that helps you retrieve an Active Record entity from a database with a URL. You know Houser is a multi-tenancy gem that can send database requests using subdomain names. But Houser is a relatively old Ruby library. For modern Rails-based SaaS apps, we wanted more flexibility. That's why we've developed Detectify. 10 | For more information, you can read here [Detectify review](https://rubygarage.org/blog/how-we-retrieve-tenant-data-in-a-multi-tenant-app). 11 | 12 | ## Installation 13 | 14 | Add this line to your application's Gemfile: 15 | 16 | `gem 'detectify', github: 'rubygarage/detectify'` 17 | 18 | and then execute: `$ bundle` 19 | 20 | Finally, restart the server to apply the changes. 21 | 22 | Detectify only supports applications built with Ruby 2.2.2 and Rails 4.2 or higher. 23 | 24 | ## Usage 25 | 26 | Start off by generating an initializer: 27 | 28 | `$ bundle exec rails g detectify:install` 29 | 30 | this will create file `config/initializers/detectify.rb` in your application directory. 31 | 32 | You can configure Detectify for your application needs via initializer. After this you can access detected entity via: `request.env['Detectify-Entity']`. 33 | 34 | ## Contributing 35 | 36 | Bug reports and pull requests are welcome on GitHub at https://github.com/rubygarage/detectify. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 37 | 38 | ## License 39 | 40 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 41 | *** 42 | RubyGarage Logo 43 | 44 | RubyGarage is a leading software development and consulting company in Eastern Europe. Our main expertise includes Ruby and Ruby on Rails, but we successfully employ other technologies to deliver the best results to our clients. [Check out our portfolio](https://rubygarage.org/portfolio) for even more exciting works! 45 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task default: :spec 7 | -------------------------------------------------------------------------------- /detectify.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'detectify/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'detectify' 8 | spec.version = Detectify::VERSION 9 | spec.authors = ['Lukyanov Fedor'] 10 | spec.email = ['fedor@rubygarage.org'] 11 | 12 | spec.license = 'MIT' 13 | spec.homepage = 'https://github.com/rubygarage/detectify' 14 | spec.summary = 'Detect ActiveRecord entity via domain or subdomain' 15 | spec.description = 'Detectify provides a simple way to retrieve an ActiveRecord entity ' \ 16 | 'based on the domain/subdomain request information.' 17 | 18 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 19 | spec.require_paths = ['lib'] 20 | spec.required_ruby_version = '>= 2.2.2' 21 | 22 | spec.add_dependency 'rack', '>= 1.6' 23 | spec.add_dependency 'activerecord', '>= 4.2' 24 | 25 | spec.add_development_dependency 'byebug', '~> 9.0' 26 | spec.add_development_dependency 'bundler', '~> 1.12' 27 | spec.add_development_dependency 'rake', '~> 10.0' 28 | spec.add_development_dependency 'rspec', '~> 3.0' 29 | spec.add_development_dependency 'fuubar', '~> 2.0' 30 | spec.add_development_dependency 'coveralls', '~> 0.8' 31 | end 32 | -------------------------------------------------------------------------------- /lib/detectify.rb: -------------------------------------------------------------------------------- 1 | require 'detectify/version' 2 | require 'detectify/config' 3 | require 'detectify/query_builder/base' 4 | require 'detectify/query_builder/sql' 5 | require 'detectify/detector' 6 | require 'detectify/middleware' 7 | 8 | module Detectify 9 | def self.configure 10 | yield(config) 11 | end 12 | 13 | def self.config 14 | @config || reset_config 15 | end 16 | 17 | def self.reset_config(config = Config.new) 18 | @config = config 19 | end 20 | 21 | def self.entity_class 22 | if config.entity_class.is_a?(String) 23 | Object.const_get(config.entity_class) 24 | else 25 | config.entity_class 26 | end 27 | end 28 | end 29 | 30 | require 'detectify/railtie' if defined?(::Rails) 31 | -------------------------------------------------------------------------------- /lib/detectify/config.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | class Config 3 | attr_accessor :entity_class, :tld_length, :ignore_urls, 4 | :domain_column, :subdomain_column 5 | 6 | def initialize 7 | @entity_class = 'Account' 8 | @tld_length = 1 9 | @ignore_urls = [] 10 | @domain_column = 'domain' 11 | @subdomain_column = 'subdomain' 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/detectify/detector.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | 3 | module Detectify 4 | class Detector 5 | attr_reader :request_uri 6 | 7 | def initialize(request_url, query_builder = QueryBuilder::SQL) 8 | @request_uri = URI(request_url) 9 | @query_builder = query_builder 10 | end 11 | 12 | def detect 13 | @entity ||= Detectify.entity_class.where(*query).first unless ignore? 14 | end 15 | 16 | private 17 | 18 | def ignore? 19 | @request_uri.to_s[Regexp.union(*Detectify.config.ignore_urls)] 20 | end 21 | 22 | def query 23 | @query_builder.new(domain, subdomain).build 24 | end 25 | 26 | def domain 27 | request_uri.host 28 | end 29 | 30 | def subdomain 31 | chunks = request_uri.host.split('.') 32 | chunks[0...(1 - Detectify.config.tld_length - 2)].join 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/detectify/middleware.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | class Middleware 3 | def initialize(app) 4 | @app = app 5 | end 6 | 7 | def call(env) 8 | request = Rack::Request.new(env) 9 | detector = Detector.new(request.url) 10 | 11 | env['Detectify-Entity'] = detector.detect 12 | 13 | @app.call(env) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/detectify/query_builder/base.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | module QueryBuilder 3 | class Base 4 | attr_reader :domain, :subdomain 5 | 6 | def initialize(domain, subdomain) 7 | @domain = domain.downcase if domain.is_a?(String) 8 | @subdomain = subdomain.downcase if subdomain.is_a?(String) 9 | end 10 | 11 | def build 12 | raise(NotImplementedError) 13 | end 14 | 15 | private 16 | 17 | def need_domain_clause? 18 | Detectify.config.domain_column && domain 19 | end 20 | 21 | def need_subdomain_clause? 22 | Detectify.config.subdomain_column && subdomain 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/detectify/query_builder/sql.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | module QueryBuilder 3 | class SQL < Base 4 | def build 5 | @query ||= begin 6 | query = ["#{domain_clause}#{or_operator}#{subdomain_clause}"] 7 | query << domain if need_domain_clause? 8 | query << subdomain if need_subdomain_clause? 9 | query.compact 10 | end 11 | end 12 | 13 | private 14 | 15 | def domain_clause 16 | "LOWER(#{Detectify.config.domain_column}) = ?" if need_domain_clause? 17 | end 18 | 19 | def subdomain_clause 20 | "LOWER(#{Detectify.config.subdomain_column}) = ?" if need_subdomain_clause? 21 | end 22 | 23 | def or_operator 24 | ' OR ' if need_domain_clause? && need_subdomain_clause? 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/detectify/railtie.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | class Railtie < Rails::Railtie 3 | initializer 'detectify' do |app| 4 | app.config.middleware.use Detectify::Middleware 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/detectify/version.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | VERSION = '1.0.5'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/generators/detectify/install_generator.rb: -------------------------------------------------------------------------------- 1 | module Detectify 2 | module Generators 3 | class InstallGenerator < Rails::Generators::Base 4 | source_root File.expand_path('../templates', __FILE__) 5 | 6 | def copy_initializer_file 7 | copy_file 'detectify.rb', 'config/initializers/detectify.rb' 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/generators/detectify/templates/detectify.rb: -------------------------------------------------------------------------------- 1 | Detectify.configure do |config| 2 | # Set the model that Detectify will use to detect entity. 3 | # Default value is 'Account'. 4 | # config.entity_class = 'Account' 5 | 6 | # Set the column that will be used to find entity by domain. 7 | # If you don't need such lookup, you can simply set 8 | # domain_column value as nil. Default value is 'domain' 9 | # config.domain_column = 'domain' 10 | 11 | # Set the column that will be used to find entity by subdomain. 12 | # If you don't need such lookup, you can simply set 13 | # subdomain_column value as nil. Default value is 'subdomain'. 14 | # config.subdomain_column = 'subdomain' 15 | 16 | # Set your top level domain length. 17 | # For more information about TLD visit http://bit.ly/1jIeoL9 18 | # By length, means count of dots in your TLD. 19 | # For example, tld_length for 'example.co.uk' domain will be 2, 20 | # for 'example.com' will be 1. Default value is 1. 21 | # config.tld_length = 1 22 | 23 | # Array of regular expressions, that will be used to determine 24 | # whether it is necessary to detect entity. You can add as much as you want, 25 | # for example, config.ignore_urls += [%r{/assets/}]. Default values is []. 26 | # config.ignore_urls += [%r{/assets/}] 27 | end 28 | -------------------------------------------------------------------------------- /spec/detectify/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify::Config do 4 | describe 'Default values' do 5 | subject { Detectify::Config.new } 6 | 7 | it { expect(subject.entity_class).to eq('Account') } 8 | it { expect(subject.tld_length).to eq(1) } 9 | it { expect(subject.ignore_urls).to eq([]) } 10 | it { expect(subject.domain_column).to eq('domain') } 11 | it { expect(subject.subdomain_column).to eq('subdomain') } 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/detectify/detectify_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify do 4 | describe '.entity_class' do 5 | let(:account_class) { Class.new } 6 | 7 | subject { Detectify.entity_class } 8 | 9 | context 'when Detectify.config.entity_class is a class' do 10 | before { Detectify.config.entity_class = account_class } 11 | 12 | it { is_expected.to eq(account_class) } 13 | end 14 | 15 | context 'when Detectify.config.entity_class is a string' do 16 | before do 17 | Detectify.config.entity_class = 'Account' 18 | Object.const_set('Account', account_class) 19 | end 20 | 21 | it { is_expected.to eq(account_class) } 22 | end 23 | 24 | after { Detectify.reset_config } 25 | end 26 | 27 | describe '.configure' do 28 | it 'allows to change config' do 29 | Detectify.configure do |config| 30 | config.entity_class = 'Some Class' 31 | config.tld_length = 2 32 | config.ignore_urls = [%r{/assets/}] 33 | config.domain_column = 'some_domain' 34 | config.subdomain_column = 'some_subdomain' 35 | end 36 | 37 | expect(Detectify.config.entity_class).to eq('Some Class') 38 | expect(Detectify.config.tld_length).to eq(2) 39 | expect(Detectify.config.ignore_urls).to eq([%r{/assets/}]) 40 | expect(Detectify.config.domain_column).to eq('some_domain') 41 | expect(Detectify.config.subdomain_column).to eq('some_subdomain') 42 | end 43 | 44 | after { Detectify.reset_config } 45 | end 46 | 47 | describe '.reset_config' do 48 | before { Detectify.config.tld_length = 5 } 49 | 50 | context 'when config passed' do 51 | let(:config) do 52 | config = Detectify::Config.new 53 | config.tld_length = 2 54 | config 55 | end 56 | 57 | subject { Detectify.reset_config(config) } 58 | 59 | it 'sets config to passed' do 60 | expect(subject.tld_length).to eq(2) 61 | end 62 | end 63 | 64 | context 'when config not passed' do 65 | subject { Detectify.reset_config } 66 | 67 | it 'sets config to default' do 68 | expect(subject.tld_length).to eq(1) 69 | end 70 | end 71 | 72 | after { Detectify.reset_config } 73 | end 74 | 75 | describe '.config' do 76 | subject { Detectify.config } 77 | 78 | it { is_expected.to be_a(Detectify::Config) } 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/detectify/detector_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify::Detector do 4 | describe '#detect' do 5 | let(:builder) { Detectify::QueryBuilder::SQL } 6 | 7 | subject { Detectify::Detector.new(url, builder).detect } 8 | 9 | context 'when path should be ignored' do 10 | let(:url) { 'https://sub.example.com/assets/some_asset.jpg' } 11 | 12 | before { Detectify.config.ignore_urls += [%r{/assets/}] } 13 | 14 | it { is_expected.to be_nil } 15 | end 16 | 17 | context 'when path should not be ignored' do 18 | let(:entity_class) { Class.new } 19 | let(:builder_double) { double('builder', build: ['some_query']) } 20 | let(:url) { 'https://sub.example.com/some_resource' } 21 | 22 | before do 23 | Detectify.config.entity_class = entity_class 24 | 25 | allow(builder).to receive(:new).with('sub.example.com', 'sub') 26 | .and_return(builder_double) 27 | 28 | allow(entity_class).to receive(:where).with('some_query') 29 | .and_return(['some_entity']) 30 | end 31 | 32 | it { is_expected.to eq('some_entity') } 33 | end 34 | 35 | after { Detectify.reset_config } 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/detectify/middleware_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify::Middleware do 4 | describe '#call' do 5 | let(:app) { ->(env) { [200, env, 'hello'] } } 6 | let(:middleware) { Detectify::Middleware.new(app) } 7 | let(:request) { Rack::MockRequest.new(middleware) } 8 | 9 | subject { request.get('/') } 10 | 11 | before do 12 | allow(Detectify::Detector).to receive(:new).with('http://example.org/') 13 | .and_return(detector_double) 14 | end 15 | 16 | context 'when entity found' do 17 | let(:detector_double) { double('detector', detect: 'some_entity') } 18 | 19 | it { expect(subject['Detectify-Entity']).to eq('some_entity') } 20 | end 21 | 22 | context 'when entity not found' do 23 | let(:detector_double) { double('detector', detect: nil) } 24 | 25 | it { expect(subject['Detectify-Entity']).to eq(nil) } 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/detectify/query_builder/base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify::QueryBuilder::Base do 4 | let(:domain) { 'DOMAIN' } 5 | let(:subdomain) { 'SUBDOMAIN' } 6 | subject { Detectify::QueryBuilder::Base.new(domain, subdomain) } 7 | 8 | describe '#initialize' do 9 | it 'sets domain in downcase' do 10 | expect(subject.domain).to eq(domain.downcase) 11 | end 12 | 13 | it 'sets subdomain in downcase' do 14 | expect(subject.subdomain).to eq(subdomain.downcase) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/detectify/query_builder/sql_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Detectify::QueryBuilder::SQL do 4 | describe '#build' do 5 | subject { Detectify::QueryBuilder::SQL.new(domain, subdomain).build } 6 | 7 | context 'with domain and subdomain columns in config' do 8 | context 'with only domain' do 9 | let(:domain) { 'example.com' } 10 | let(:subdomain) { nil } 11 | 12 | it { is_expected.to eq(['LOWER(domain) = ?', 'example.com']) } 13 | end 14 | 15 | context 'with only subdomain' do 16 | let(:domain) { nil } 17 | let(:subdomain) { 'example' } 18 | 19 | it { is_expected.to eq(['LOWER(subdomain) = ?', 'example']) } 20 | end 21 | 22 | context 'with domain and subdomain' do 23 | let(:domain) { 'example.com' } 24 | let(:subdomain) { 'example' } 25 | 26 | it do 27 | is_expected.to eq([ 28 | 'LOWER(domain) = ? OR LOWER(subdomain) = ?', 'example.com', 'example' 29 | ]) 30 | end 31 | end 32 | end 33 | 34 | context 'with domain column in config' do 35 | before { Detectify.config.subdomain_column = nil } 36 | 37 | context 'with only domain' do 38 | let(:domain) { 'example.com' } 39 | let(:subdomain) { nil } 40 | 41 | it { is_expected.to eq(['LOWER(domain) = ?', 'example.com']) } 42 | end 43 | 44 | context 'with only subdomain' do 45 | let(:domain) { nil } 46 | let(:subdomain) { 'example' } 47 | 48 | it { is_expected.to eq(['']) } 49 | end 50 | 51 | context 'with domain and subdomain' do 52 | let(:domain) { 'example.com' } 53 | let(:subdomain) { 'example' } 54 | 55 | it { is_expected.to eq(['LOWER(domain) = ?', 'example.com']) } 56 | end 57 | 58 | after { Detectify.reset_config } 59 | end 60 | 61 | context 'with subdomain column in config' do 62 | before { Detectify.config.domain_column = nil } 63 | 64 | context 'with only domain' do 65 | let(:domain) { 'example.com' } 66 | let(:subdomain) { nil } 67 | 68 | it { is_expected.to eq(['']) } 69 | end 70 | 71 | context 'with only subdomain' do 72 | let(:domain) { nil } 73 | let(:subdomain) { 'example' } 74 | 75 | it { is_expected.to eq(['LOWER(subdomain) = ?', 'example']) } 76 | end 77 | 78 | context 'with domain and subdomain' do 79 | let(:domain) { 'example.com' } 80 | let(:subdomain) { 'example' } 81 | 82 | it { is_expected.to eq(['LOWER(subdomain) = ?', 'example']) } 83 | end 84 | 85 | after { Detectify.reset_config } 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | Coveralls.wear! 3 | 4 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 5 | 6 | RSpec.configure do |config| 7 | config.order = :random 8 | end 9 | 10 | require 'rack' 11 | require 'detectify' 12 | --------------------------------------------------------------------------------