activerecord-tablefree 3.0.0
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 +9 -0
- data/.rspec +1 -0
- data/.travis.yml +10 -0
- data/Appraisals +11 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +25 -0
- data/README.md +175 -0
- data/Rakefile +48 -0
- data/activerecord-tablefree.gemspec +46 -0
- data/features/basic_integration.feature +16 -0
- data/features/step_definitions/rails_steps.rb +141 -0
- data/features/step_definitions/tablefree.rb +37 -0
- data/features/step_definitions/web_steps.rb +140 -0
- data/features/support/env.rb +15 -0
- data/features/support/paths.rb +28 -0
- data/features/support/rails.rb +52 -0
- data/features/support/selectors.rb +19 -0
- data/gemfiles/rails50.gemfile +11 -0
- data/gemfiles/rails51.gemfile +11 -0
- data/init.rb +4 -0
- data/lib/activerecord-tablefree.rb +318 -0
- data/lib/activerecord-tablefree/version.rb +7 -0
- data/spec/lib/activerecord-tablefree_spec.rb +284 -0
- data/spec/spec_helper.rb +2 -0
- metadata +300 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
Given /^I delete all migrations$/ do
|
2
|
+
steps %{
|
3
|
+
When I successfully run `bash -c 'rm db/migrate/*.rb'`
|
4
|
+
}
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^I update my new user model to be tablefree$/ do
|
8
|
+
in_current_dir do
|
9
|
+
file_name = 'app/models/user.rb'
|
10
|
+
content = File.read(file_name)
|
11
|
+
if framework_version < "3.0"
|
12
|
+
content = "require 'activerecord-tablefree'\n" + content
|
13
|
+
end
|
14
|
+
|
15
|
+
content.gsub!(/^(class .* < ActiveRecord::Base)$/, "\\1\n" + <<-TABLELESS)
|
16
|
+
has_no_table
|
17
|
+
column :id, :integer
|
18
|
+
column :name, :string
|
19
|
+
|
20
|
+
TABLELESS
|
21
|
+
File.open(file_name, 'w') { |f| f << content }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /^I update my users controller to render instead of redirect$/ do
|
26
|
+
in_current_dir do
|
27
|
+
transform_file('app/controllers/users_controller.rb') do |content|
|
28
|
+
##Changes in #create method
|
29
|
+
content.gsub!(/@user = User.new\((.*?)\)/,
|
30
|
+
'@user = User.new(\1); @user.id = 1')
|
31
|
+
content.gsub!("if @user.save",
|
32
|
+
"if @user.valid?")
|
33
|
+
content.gsub!(/redirect_to([\( ])@user, .*?([\)]| \}|$)/,
|
34
|
+
"render\\1:action => 'show'\\2")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# TL;DR: YOU SHOULD DELETE THIS FILE
|
2
|
+
#
|
3
|
+
# This file was generated by Cucumber-Rails and is only here to get you a head start
|
4
|
+
# These step definitions are thin wrappers around the Capybara/Webrat API that lets you
|
5
|
+
# visit pages, interact with widgets and make assertions about page content.
|
6
|
+
#
|
7
|
+
# If you use these step definitions as basis for your features you will quickly end up
|
8
|
+
# with features that are:
|
9
|
+
#
|
10
|
+
# * Hard to maintain
|
11
|
+
# * Verbose to read
|
12
|
+
#
|
13
|
+
# A much better approach is to write your own higher level step definitions, following
|
14
|
+
# the advice in the following blog posts:
|
15
|
+
#
|
16
|
+
# * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
|
17
|
+
# * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
|
18
|
+
# * http://elabs.se/blog/15-you-re-cuking-it-wrong
|
19
|
+
#
|
20
|
+
|
21
|
+
|
22
|
+
require 'uri'
|
23
|
+
require 'cgi'
|
24
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
25
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
|
26
|
+
|
27
|
+
module WithinHelpers
|
28
|
+
def with_scope(locator)
|
29
|
+
locator ? within(*selector_for(locator)) { yield } : yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
World(WithinHelpers)
|
33
|
+
|
34
|
+
# Single-line step scoper
|
35
|
+
When /^(.*) within (.*[^:])$/ do |step, parent|
|
36
|
+
with_scope(parent) { When step }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Multi-line step scoper
|
40
|
+
When /^(.*) within (.*[^:]):$/ do |step, parent, table_or_string|
|
41
|
+
with_scope(parent) { When "#{step}:", table_or_string }
|
42
|
+
end
|
43
|
+
|
44
|
+
Given /^(?:|I )am on (.+)$/ do |page_name|
|
45
|
+
visit path_to(page_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
When /^(?:|I )go to (.+)$/ do |page_name|
|
49
|
+
visit path_to(page_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
When /^(?:|I )press "([^"]*)"$/ do |button|
|
53
|
+
click_button(button)
|
54
|
+
end
|
55
|
+
|
56
|
+
When /^(?:|I )follow "([^"]*)"$/ do |link|
|
57
|
+
click_link(link)
|
58
|
+
end
|
59
|
+
|
60
|
+
When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
|
61
|
+
fill_in(field, :with => value)
|
62
|
+
end
|
63
|
+
|
64
|
+
When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
|
65
|
+
fill_in(field, :with => value)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Use this to fill in an entire form with data from a table. Example:
|
69
|
+
#
|
70
|
+
# When I fill in the following:
|
71
|
+
# | Account Number | 5002 |
|
72
|
+
# | Expiry date | 2009-11-01 |
|
73
|
+
# | Note | Nice guy |
|
74
|
+
# | Wants Email? | |
|
75
|
+
#
|
76
|
+
# TODO: Add support for checkbox, select og option
|
77
|
+
# based on naming conventions.
|
78
|
+
#
|
79
|
+
When /^(?:|I )fill in the following:$/ do |fields|
|
80
|
+
fields.rows_hash.each do |name, value|
|
81
|
+
When %{I fill in "#{name}" with "#{value}"}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
|
86
|
+
select(value, :from => field)
|
87
|
+
end
|
88
|
+
|
89
|
+
When /^(?:|I )check "([^"]*)"$/ do |field|
|
90
|
+
check(field)
|
91
|
+
end
|
92
|
+
|
93
|
+
When /^(?:|I )uncheck "([^"]*)"$/ do |field|
|
94
|
+
uncheck(field)
|
95
|
+
end
|
96
|
+
|
97
|
+
When /^(?:|I )choose "([^"]*)"$/ do |field|
|
98
|
+
choose(field)
|
99
|
+
end
|
100
|
+
|
101
|
+
When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
|
102
|
+
attach_file(field, File.expand_path(path))
|
103
|
+
end
|
104
|
+
|
105
|
+
Then /^(?:|I )should (not )?see "([^"]*)"$/ do |negate, text|
|
106
|
+
should_name = negate ? :should_not : :should
|
107
|
+
if page.respond_to? should_name
|
108
|
+
page.send should_name, have_content(text)
|
109
|
+
else
|
110
|
+
assert(negate ? page.has_no_content?(text) : page.has_content?(text))
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Then /^(?:|I )should (not )?see \/([^\/]*)\/$/ do |negate, regexp|
|
115
|
+
regexp = Regexp.new(regexp)
|
116
|
+
should_name = negate ? :should_not : :should
|
117
|
+
if page.respond_to? should_name
|
118
|
+
page.send should_name, have_xpath('//*', :text => regexp)
|
119
|
+
else
|
120
|
+
assert(negate ? page.has_no_xpath?('//*', :text => regexp) : page.has_xpath?('//*', :text => regexp))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
Then /^(?:|I )should be on (.+)$/ do |page_name|
|
125
|
+
current_path = URI.parse(current_url).path
|
126
|
+
expect(current_path).to eq path_to(page_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
|
130
|
+
query = URI.parse(current_url).query
|
131
|
+
actual_params = query ? CGI.parse(query) : {}
|
132
|
+
expected_params = {}
|
133
|
+
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
134
|
+
|
135
|
+
expect(actual_params).to eq expected_params
|
136
|
+
end
|
137
|
+
|
138
|
+
Then /^show me the page$/ do
|
139
|
+
save_and_open_page
|
140
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'aruba/cucumber'
|
11
|
+
require 'capybara/cucumber'
|
12
|
+
|
13
|
+
Before do
|
14
|
+
@aruba_timeout_seconds = 120
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
# Maps a name to a path. Used by the
|
3
|
+
#
|
4
|
+
# When /^I go to (.+)$/ do |page_name|
|
5
|
+
#
|
6
|
+
# step definition in web_steps.rb
|
7
|
+
#
|
8
|
+
def path_to(page_name)
|
9
|
+
case page_name
|
10
|
+
|
11
|
+
when /the home\s?page/
|
12
|
+
'/'
|
13
|
+
when /the new user page/
|
14
|
+
'/users/new'
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
page_name =~ /the (.*) page/
|
18
|
+
path_components = $1.split(/\s+/)
|
19
|
+
self.send(path_components.push('path').join('_').to_sym)
|
20
|
+
rescue Object => e
|
21
|
+
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
22
|
+
"Now, go and add a mapping in #{__FILE__}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
World(NavigationHelpers)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
2
|
+
APP_NAME = 'testapp'.freeze
|
3
|
+
BUNDLE_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE)
|
4
|
+
ORIGINAL_BUNDLE_VARS = Hash[ENV.select{ |key,value| BUNDLE_ENV_VARS.include?(key) }]
|
5
|
+
|
6
|
+
ENV['RAILS_ENV'] = 'test'
|
7
|
+
|
8
|
+
Before do
|
9
|
+
ENV['BUNDLE_GEMFILE'] = File.join(Dir.pwd, ENV['BUNDLE_GEMFILE']) unless ENV['BUNDLE_GEMFILE'].start_with?(Dir.pwd)
|
10
|
+
@framework_version = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ORIGINAL_BUNDLE_VARS.each_pair do |key, value|
|
15
|
+
ENV[key] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
When /^I reset Bundler environment variable$/ do
|
20
|
+
BUNDLE_ENV_VARS.each do |key|
|
21
|
+
ENV[key] = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module RailsCommandHelpers
|
26
|
+
def framework_version?(version_string)
|
27
|
+
framework_version =~ /^#{version_string}/
|
28
|
+
end
|
29
|
+
|
30
|
+
def framework_version
|
31
|
+
@framework_version ||= `rails -v`[/^Rails (.+)$/, 1]
|
32
|
+
end
|
33
|
+
|
34
|
+
def framework_major_version
|
35
|
+
framework_version.split(".").first.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def new_application_command(app_name)
|
39
|
+
framework_major_version >= 3 ? "rails new #{app_name} --skip-sprockets --skip-javascript --skip-bundle" : "rails #{app_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def generator_command
|
43
|
+
framework_major_version >= 3 ? "rails generate" : "script/generate"
|
44
|
+
end
|
45
|
+
|
46
|
+
def runner_command
|
47
|
+
framework_major_version >= 3 ? "rails runner" : "script/runner"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
World(RailsCommandHelpers)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HtmlSelectorsHelpers
|
2
|
+
# Maps a name to a selector. Used primarily by the
|
3
|
+
#
|
4
|
+
# When /^(.+) within (.+)$/ do |step, scope|
|
5
|
+
#
|
6
|
+
# step definitions in web_steps.rb
|
7
|
+
#
|
8
|
+
def selector_for(locator)
|
9
|
+
case locator
|
10
|
+
when "the page"
|
11
|
+
"html > body"
|
12
|
+
else
|
13
|
+
raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
|
14
|
+
"Now, go and add a mapping in #{__FILE__}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
World(HtmlSelectorsHelpers)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "mime-types", "< 2.0", :platform => :ruby_18
|
6
|
+
gem "rubyzip", "< 1.0", :platform => :ruby_18
|
7
|
+
gem "byebug"
|
8
|
+
gem "rails", "~> 5.0.0"
|
9
|
+
gem "jquery-rails"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "mime-types", "< 2.0", :platform => :ruby_18
|
6
|
+
gem "rubyzip", "< 1.0", :platform => :ruby_18
|
7
|
+
gem "byebug"
|
8
|
+
gem "rails", "~> 5.1.0"
|
9
|
+
gem "jquery-rails"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
data/init.rb
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
# See #ActiveRecord::Tablefree
|
2
|
+
require 'activerecord-tablefree/version'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
|
6
|
+
# = ActiveRecord::Tablefree
|
7
|
+
#
|
8
|
+
# Allow classes to behave like ActiveRecord models, but without an associated
|
9
|
+
# database table. A great way to capitalize on validations. Based on the
|
10
|
+
# original post at http://www.railsweenie.com/forums/2/topics/724 (which seems
|
11
|
+
# to have disappeared from the face of the earth).
|
12
|
+
#
|
13
|
+
# = Example usage
|
14
|
+
#
|
15
|
+
# class ContactMessage < ActiveRecord::Base
|
16
|
+
#
|
17
|
+
# has_no_table
|
18
|
+
#
|
19
|
+
# column :name, :string
|
20
|
+
# column :email, :string
|
21
|
+
# column :message, :string
|
22
|
+
#
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# msg = ContactMessage.new( params[:msg] )
|
26
|
+
# if msg.valid?
|
27
|
+
# ContactMessageSender.deliver_message( msg )
|
28
|
+
# redirect_to :action => :sent
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
module Tablefree
|
32
|
+
require 'active_record'
|
33
|
+
|
34
|
+
class NoDatabase < StandardError; end
|
35
|
+
class Unsupported < StandardError; end
|
36
|
+
|
37
|
+
def self.included( base ) #:nodoc:
|
38
|
+
base.send :extend, ActsMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
module ActsMethods #:nodoc:
|
42
|
+
|
43
|
+
# A model that needs to be tablefree will call this method to indicate
|
44
|
+
# it.
|
45
|
+
def has_no_table(options = {:database => :fail_fast})
|
46
|
+
raise ArgumentError.new("Invalid database option '#{options[:database]}'") unless [:fail_fast, :pretend_success].member? options[:database]
|
47
|
+
# keep our options handy
|
48
|
+
class_attribute :tablefree_options
|
49
|
+
self.tablefree_options = {
|
50
|
+
:database => options[:database],
|
51
|
+
:columns_hash => {}
|
52
|
+
}
|
53
|
+
|
54
|
+
# extend
|
55
|
+
extend ActiveRecord::Tablefree::SingletonMethods
|
56
|
+
extend ActiveRecord::Tablefree::ClassMethods
|
57
|
+
|
58
|
+
# include
|
59
|
+
include ActiveRecord::Tablefree::InstanceMethods
|
60
|
+
|
61
|
+
# setup columns
|
62
|
+
include ActiveModel::AttributeAssignment
|
63
|
+
include ActiveRecord::ModelSchema
|
64
|
+
end
|
65
|
+
|
66
|
+
def tablefree?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
module SingletonMethods
|
73
|
+
|
74
|
+
# Used internally by ActiveRecord 5. This is the special hook that makes everything else work.
|
75
|
+
def load_schema!
|
76
|
+
@columns_hash = tablefree_options[:columns_hash].except(*ignored_columns)
|
77
|
+
@columns_hash.each do |name, column|
|
78
|
+
define_attribute(
|
79
|
+
name,
|
80
|
+
connection.lookup_cast_type_from_column(column),
|
81
|
+
default: column.default,
|
82
|
+
user_provided_default: false
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Register a new column.
|
88
|
+
def column(name, sql_type = nil, default = nil, null = true)
|
89
|
+
cast_type = "ActiveRecord::Type::#{sql_type.to_s.camelize}".constantize.new
|
90
|
+
tablefree_options[:columns_hash][name.to_s] = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, cast_type, sql_type.to_s, null)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Register a set of columns with the same SQL type
|
94
|
+
def add_columns(sql_type, *args)
|
95
|
+
args.each do |col|
|
96
|
+
column col, sql_type
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def destroy(*args)
|
101
|
+
case tablefree_options[:database]
|
102
|
+
when :pretend_success
|
103
|
+
self.new()
|
104
|
+
when :fail_fast
|
105
|
+
raise NoDatabase.new("Can't #destroy on Tablefree class")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def destroy_all(*_args)
|
110
|
+
case tablefree_options[:database]
|
111
|
+
when :pretend_success
|
112
|
+
[]
|
113
|
+
when :fail_fast
|
114
|
+
raise NoDatabase.new("Can't #destroy_all on Tablefree class")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
case ActiveRecord::VERSION::MAJOR
|
119
|
+
when 5
|
120
|
+
def find_by_sql(*args)
|
121
|
+
case tablefree_options[:database]
|
122
|
+
when :pretend_success
|
123
|
+
[]
|
124
|
+
when :fail_fast
|
125
|
+
raise NoDatabase.new("Can't #find_by_sql on Tablefree class")
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
else
|
130
|
+
raise Unsupported.new("Unsupported ActiveRecord version")
|
131
|
+
end
|
132
|
+
|
133
|
+
def transaction(&block)
|
134
|
+
# case tablefree_options[:database]
|
135
|
+
# when :pretend_success
|
136
|
+
@_current_transaction_records ||= []
|
137
|
+
yield
|
138
|
+
# when :fail_fast
|
139
|
+
# raise NoDatabase.new("Can't #transaction on Tablefree class")
|
140
|
+
# end
|
141
|
+
end
|
142
|
+
|
143
|
+
def tablefree?
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
147
|
+
def table_exists?
|
148
|
+
false
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module ClassMethods
|
153
|
+
|
154
|
+
def from_query_string(query_string)
|
155
|
+
unless query_string.blank?
|
156
|
+
params = query_string.split('&').collect do |chunk|
|
157
|
+
next if chunk.empty?
|
158
|
+
key, value = chunk.split('=', 2)
|
159
|
+
next if key.empty?
|
160
|
+
value = value.nil? ? nil : CGI.unescape(value)
|
161
|
+
[ CGI.unescape(key), value ]
|
162
|
+
end.compact.to_h
|
163
|
+
|
164
|
+
new(params)
|
165
|
+
else
|
166
|
+
new
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def connection
|
171
|
+
conn = Object.new()
|
172
|
+
def conn.quote_table_name(*_args)
|
173
|
+
""
|
174
|
+
end
|
175
|
+
def conn.quote_column_name(*_args)
|
176
|
+
""
|
177
|
+
end
|
178
|
+
def conn.substitute_at(*_args)
|
179
|
+
nil
|
180
|
+
end
|
181
|
+
def conn.schema_cache(*_args)
|
182
|
+
schema_cache = Object.new()
|
183
|
+
def schema_cache.columns_hash(*_args)
|
184
|
+
Hash.new()
|
185
|
+
end
|
186
|
+
schema_cache
|
187
|
+
end
|
188
|
+
# Fixes Issue #17. https://github.com/softace/activerecord-tablefree/issues/17
|
189
|
+
# The following method is from the ActiveRecord gem: /lib/active_record/connection_adapters/abstract/database_statements.rb .
|
190
|
+
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
|
191
|
+
#
|
192
|
+
# The +limit+ may be anything that can evaluate to a string via #to_s. It
|
193
|
+
# should look like an integer, or a comma-delimited list of integers, or
|
194
|
+
# an Arel SQL literal.
|
195
|
+
#
|
196
|
+
# Returns Integer and Arel::Nodes::SqlLiteral limits as is.
|
197
|
+
# Returns the sanitized limit parameter, either as an integer, or as a
|
198
|
+
# string which contains a comma-delimited list of integers.
|
199
|
+
def conn.sanitize_limit(limit)
|
200
|
+
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
201
|
+
limit
|
202
|
+
elsif limit.to_s.include?(',')
|
203
|
+
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
204
|
+
else
|
205
|
+
Integer(limit)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Called by bound_attributes in /lib/active_record/relation/query_methods.rb
|
210
|
+
# Returns a SQL string with the from, join, where, and having clauses, in addition to the limit and offset.
|
211
|
+
def conn.combine_bind_parameters(**_args)
|
212
|
+
""
|
213
|
+
end
|
214
|
+
|
215
|
+
def conn.lookup_cast_type_from_column(*_args)
|
216
|
+
lct = Object.new
|
217
|
+
def lct.assert_valid_value(*_args)
|
218
|
+
true
|
219
|
+
end
|
220
|
+
# Needed for Rails 5.0
|
221
|
+
def lct.serialize(args)
|
222
|
+
args
|
223
|
+
end
|
224
|
+
def lct.deserialize(args)
|
225
|
+
args
|
226
|
+
end
|
227
|
+
def lct.cast(args)
|
228
|
+
args
|
229
|
+
end
|
230
|
+
def lct.changed?(*_args)
|
231
|
+
false
|
232
|
+
end
|
233
|
+
def lct.changed_in_place?(*_args)
|
234
|
+
false
|
235
|
+
end
|
236
|
+
lct
|
237
|
+
end
|
238
|
+
|
239
|
+
# This is used in the StatementCache object. It returns an object that
|
240
|
+
# can be used to query the database repeatedly.
|
241
|
+
def conn.cacheable_query(arel) # :nodoc:
|
242
|
+
if prepared_statements
|
243
|
+
ActiveRecord::StatementCache.query visitor, arel.ast
|
244
|
+
else
|
245
|
+
ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
|
246
|
+
end
|
247
|
+
end
|
248
|
+
conn
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
module InstanceMethods
|
254
|
+
|
255
|
+
def to_query_string(prefix = nil)
|
256
|
+
attributes.to_a.collect{|(name,value)| escaped_var_name(name, prefix) + "=" + escape_for_url(value) if value }.compact.join("&")
|
257
|
+
end
|
258
|
+
|
259
|
+
def quote_value(_value, _column = nil)
|
260
|
+
""
|
261
|
+
end
|
262
|
+
|
263
|
+
%w(create create_record _create_record update update_record _update_record).each do |method_name|
|
264
|
+
define_method(method_name) do |*args|
|
265
|
+
case self.class.tablefree_options[:database]
|
266
|
+
when :pretend_success
|
267
|
+
true
|
268
|
+
when :fail_fast
|
269
|
+
raise NoDatabase.new("Can't ##{method_name} a Tablefree object")
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def destroy
|
275
|
+
case self.class.tablefree_options[:database]
|
276
|
+
when :pretend_success
|
277
|
+
@destroyed = true
|
278
|
+
freeze
|
279
|
+
when :fail_fast
|
280
|
+
raise NoDatabase.new("Can't #destroy a Tablefree object")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def reload(*args)
|
285
|
+
case self.class.tablefree_options[:database]
|
286
|
+
when :pretend_success
|
287
|
+
self
|
288
|
+
when :fail_fast
|
289
|
+
raise NoDatabase.new("Can't #reload a Tablefree object")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def add_to_transaction
|
294
|
+
end
|
295
|
+
|
296
|
+
private
|
297
|
+
|
298
|
+
def escaped_var_name(name, prefix = nil)
|
299
|
+
prefix ? "#{URI.escape(prefix)}[#{URI.escape(name)}]" : URI.escape(name)
|
300
|
+
end
|
301
|
+
|
302
|
+
def escape_for_url(value)
|
303
|
+
case value
|
304
|
+
when true then "1"
|
305
|
+
when false then "0"
|
306
|
+
when nil then ""
|
307
|
+
else URI.escape(value.to_s)
|
308
|
+
end
|
309
|
+
rescue
|
310
|
+
""
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
ActiveRecord::Base.send( :include, ActiveRecord::Tablefree )
|