introspective_grape 0.0.4 → 0.1.9

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +1164 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -2
  7. data/CHANGELOG.md +58 -0
  8. data/Gemfile +5 -3
  9. data/README.md +70 -17
  10. data/introspective_grape.gemspec +8 -8
  11. data/lib/.DS_Store +0 -0
  12. data/lib/introspective_grape/api.rb +177 -216
  13. data/lib/introspective_grape/camel_snake.rb +28 -59
  14. data/lib/introspective_grape/filters.rb +66 -0
  15. data/lib/introspective_grape/formatter/camel_json.rb +14 -0
  16. data/lib/introspective_grape/helpers.rb +63 -0
  17. data/lib/introspective_grape/traversal.rb +54 -0
  18. data/lib/introspective_grape/version.rb +1 -1
  19. data/lib/introspective_grape.rb +11 -0
  20. data/spec/.DS_Store +0 -0
  21. data/spec/dummy/Gemfile +5 -3
  22. data/spec/dummy/app/api/.DS_Store +0 -0
  23. data/spec/dummy/app/api/api_helpers.rb +5 -6
  24. data/spec/dummy/app/api/dummy/chat_api.rb +1 -2
  25. data/spec/dummy/app/api/dummy/company_api.rb +16 -1
  26. data/spec/dummy/app/api/dummy/location_api.rb +3 -3
  27. data/spec/dummy/app/api/dummy/project_api.rb +1 -0
  28. data/spec/dummy/app/api/dummy/sessions.rb +4 -8
  29. data/spec/dummy/app/api/dummy/user_api.rb +3 -1
  30. data/spec/dummy/app/api/dummy_api.rb +6 -6
  31. data/spec/dummy/app/api/error_handlers.rb +2 -2
  32. data/spec/dummy/app/models/chat_user.rb +1 -1
  33. data/spec/dummy/app/models/image.rb +2 -2
  34. data/spec/dummy/app/models/role.rb +1 -1
  35. data/spec/dummy/app/models/user/chatter.rb +6 -6
  36. data/spec/dummy/app/models/user_project_job.rb +3 -3
  37. data/spec/dummy/config/application.rb +1 -1
  38. data/spec/dummy/db/migrate/20150824215701_create_images.rb +3 -3
  39. data/spec/dummy/db/schema.rb +1 -1
  40. data/spec/models/image_spec.rb +1 -1
  41. data/spec/models/role_spec.rb +5 -5
  42. data/spec/models/user_location_spec.rb +2 -2
  43. data/spec/models/user_project_job_spec.rb +1 -1
  44. data/spec/rails_helper.rb +3 -1
  45. data/spec/requests/company_api_spec.rb +28 -0
  46. data/spec/requests/location_api_spec.rb +19 -2
  47. data/spec/requests/project_api_spec.rb +34 -3
  48. data/spec/requests/sessions_api_spec.rb +1 -1
  49. data/spec/requests/user_api_spec.rb +24 -3
  50. data/spec/support/blueprints.rb +3 -3
  51. data/spec/support/location_helper.rb +26 -21
  52. data/spec/support/request_helpers.rb +1 -3
  53. metadata +58 -28
  54. data/spec/dummy/app/api/active_record_helpers.rb +0 -17
@@ -0,0 +1,66 @@
1
+ module IntrospectiveGrape::Filters
2
+ #
3
+ # Allow filters on all whitelisted model attributes (from api_params)
4
+ #
5
+ def simple_filters(klass, model, api_params)
6
+ @simple_filters ||= api_params.select {|p| p.is_a? Symbol }.map { |field|
7
+ (klass.param_type(model,field) == DateTime ? ["#{field}_start", "#{field}_end"] : field.to_s)
8
+ }.flatten
9
+ end
10
+
11
+ def timestamp_filter(klass,model,field)
12
+ filter = field.sub(/_(end|start)\z/,'')
13
+ if field =~ /_(end|start)\z/ && klass.param_type(model,filter) == DateTime
14
+ filter
15
+ else
16
+ false
17
+ end
18
+ end
19
+
20
+ def identifier_filter(klass,model,field)
21
+ if field.ends_with?('id') && klass.param_type(model,field) == Integer
22
+ field
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ def declare_filter_params(dsl, klass, model, api_params)
29
+ # Declare optional parameters for filtering parameters, create two parameters per
30
+ # timestamp, a Start and an End, to apply a date range.
31
+ simple_filters(klass, model, api_params).each do |field|
32
+ if timestamp_filter(klass,model,field)
33
+ terminal = field.ends_with?("_start") ? "initial" : "terminal"
34
+ dsl.optional field, type: klass.param_type(model,field), description: "Constrain #{field} by #{terminal} date."
35
+ elsif identifier_filter(klass,model,field)
36
+ dsl.optional field, type: Array[Integer], coerce_with: ->(val) { val.split(',') }
37
+ else
38
+ dsl.optional field, type: klass.param_type(model,field), description: "Filter on #{field} by value."
39
+ end
40
+ end
41
+ dsl.optional :filter, type: String, description: "JSON of conditions for query. If you're familiar with ActiveRecord's query conventions you can build more complex filters, e.g. against included child associations, e.g. {\"<association_name>_<parent>\":{\"field\":\"value\"}}"
42
+
43
+ end
44
+
45
+ def apply_filter_params(klass, model, api_params, params, records)
46
+ simple_filters(klass, model, api_params).each do |field|
47
+ next if params[field].blank?
48
+
49
+ if timestamp_filter(klass,model,field)
50
+ op = field.ends_with?("_start") ? ">=" : "<="
51
+ records = records.where("#{timestamp_filter(klass,model,field)} #{op} ?", Time.zone.parse(params[field]))
52
+ else
53
+ records = records.where(field => params[field])
54
+ end
55
+ end
56
+
57
+ if params[:filter].present?
58
+ filters = JSON.parse( params[:filter].delete('\\') )
59
+ filters.each do |key, value|
60
+ records = records.where(key => value) if value.present?
61
+ end
62
+ end
63
+
64
+ records
65
+ end
66
+ end
@@ -0,0 +1,14 @@
1
+ # Add a formatter to grape that converts all snake case hash keys from ruby to camel case.
2
+ module IntrospectiveGrape
3
+ module Formatter
4
+ module CamelJson
5
+ def self.call(object, _env)
6
+ if object.respond_to?(:to_json)
7
+ JSON.parse(object.to_json).with_camel_keys.to_json
8
+ else
9
+ MultiJson.dump(object).with_camel_keys.to_json
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ module IntrospectiveGrape::Helpers
2
+ API_ACTIONS = [:index,:show,:create,:update,:destroy].freeze
3
+ def authentication_method=(method)
4
+ # IntrospectiveGrape::API.authentication_method=
5
+ @authentication_method = method
6
+ end
7
+
8
+ def authentication_method(context)
9
+ # Default to "authenticate!" or as grape docs once suggested, "authorize!"
10
+ if @authentication_method
11
+ @authentication_method
12
+ elsif context.respond_to?('authenticate!')
13
+ 'authenticate!'
14
+ elsif context.respond_to?('authorize!')
15
+ 'authorize!'
16
+ end
17
+ end
18
+
19
+ def paginate(args={})
20
+ @pagination = args
21
+ end
22
+
23
+ def pagination
24
+ @pagination
25
+ end
26
+
27
+ def exclude_actions(model, *args)
28
+ @exclude_actions ||= {}; @exclude_actions[model.name] ||= []
29
+ args.flatten!
30
+ args = API_ACTIONS if args.include?(:all)
31
+ args = [] if args.include?(:none)
32
+
33
+ undefined_actions = args.compact-API_ACTIONS
34
+ raise "#{model.name} defines invalid actions: #{undefined_actions}" if undefined_actions.present?
35
+
36
+ @exclude_actions[model.name] = args.present? ? args.compact : @exclude_actions[model.name] || []
37
+ end
38
+
39
+ def include_actions(model, *args)
40
+ @exclude_actions ||= {}; @exclude_actions[model.name] ||= []
41
+ @exclude_actions[model.name] = API_ACTIONS-exclude_actions(model, args)
42
+ end
43
+
44
+
45
+ def default_includes(model, *args)
46
+ @default_includes ||= {}
47
+ @default_includes[model.name] = args.present? ? args.flatten : @default_includes[model.name] || []
48
+ end
49
+
50
+ def whitelist(whitelist=nil)
51
+ return @whitelist if !whitelist
52
+ @whitelist = whitelist
53
+ end
54
+
55
+ def skip_presence_validations(fields=nil)
56
+ return @skip_presence_fields||[] if !fields
57
+ @skip_presence_fields = [fields].flatten
58
+ end
59
+
60
+
61
+ end
62
+
63
+
@@ -0,0 +1,54 @@
1
+ module IntrospectiveGrape::Traversal
2
+ # For deeply nested endpoints we want to present the record being affected, these
3
+ # methods traverse down from the parent instance to the child model associations
4
+ # of the deeply nested route.
5
+
6
+ def find_leaves(routes, record, params)
7
+ # Traverse down our route and find the leaf's siblings from its parent, e.g.
8
+ # project/#/teams/#/team_users ~> project.find.teams.find.team_users
9
+ # (the traversal of the intermediate nodes occurs in find_leaf())
10
+ return record if routes.size < 2 # the leaf is the root
11
+ record = find_leaf(routes, record, params)
12
+ if record
13
+ assoc = routes.last
14
+ if assoc.many?
15
+ leaves = record.send( assoc.reflection.name ).includes( default_includes(assoc.model) )
16
+ verify_records_found(leaves, routes)
17
+ leaves
18
+ else
19
+ # has_one associations don't return a CollectionProxy and so don't support
20
+ # eager loading.
21
+ record.send( assoc.reflection.name )
22
+ end
23
+ end
24
+ end
25
+
26
+ def verify_records_found(leaves, routes)
27
+ unless (leaves.map(&:class) - [routes.last.model]).empty?
28
+ raise ActiveRecord::RecordNotFound.new("Records contain the wrong models, they should all be #{routes.last.model.name}, found #{records.map(&:class).map(&:name).join(',')}")
29
+ end
30
+ end
31
+
32
+ def find_leaf(routes, record, params)
33
+ return record unless routes.size > 1
34
+ # For deeply nested routes we need to search from the root of the API to the leaf
35
+ # of its nested associations in order to guarantee the validity of the relationship,
36
+ # the authorization on the parent model, and the sanity of passed parameters.
37
+ routes[1..-1].each_with_index do |r|
38
+ if record && params[r.key]
39
+ ref = r.reflection
40
+ record = record.send(ref.name).where( id: params[r.key] ).first if ref
41
+ end
42
+ end
43
+
44
+ verify_record_found(routes, params, record)
45
+ record
46
+ end
47
+
48
+ def verify_record_found(routes, params, record)
49
+ if params[routes.last.key] && record.class != routes.last.model
50
+ raise ActiveRecord::RecordNotFound.new("No #{routes.last.model.name} with ID '#{params[routes.last.key]}'")
51
+ end
52
+ end
53
+
54
+ end
@@ -1,3 +1,3 @@
1
1
  module IntrospectiveGrape
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.9".freeze
3
3
  end
@@ -1,4 +1,15 @@
1
1
  module IntrospectiveGrape
2
2
  autoload :API, 'introspective_grape/api'
3
3
  autoload :CamelSnake, 'introspective_grape/camel_snake'
4
+ autoload :Filters, 'introspective_grape/filters'
5
+ autoload :Helpers, 'introspective_grape/helpers'
6
+ autoload :Traversal, 'introspective_grape/traversal'
7
+
8
+ module Formatter
9
+ autoload :CamelJson, 'introspective_grape/formatter/camel_json'
10
+ end
11
+
12
+ def self.config
13
+ @config = OpenStruct.new(camelize_parameters: true)
14
+ end
4
15
  end
data/spec/.DS_Store ADDED
Binary file
data/spec/dummy/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
-
1
+ source 'https://rubygems.org'
2
+ gem 'grape-kaminari'
2
3
  gem 'pundit'
3
- gem 'paperclip', '3.4.2'
4
- gem 'delayed_paperclip', git: 'https://github.com/buermann/delayed_paperclip.git'
4
+ #gem 'byebug'
5
+ gem 'paperclip'
6
+ gem 'delayed_paperclip'
Binary file
@@ -1,5 +1,4 @@
1
1
  module ApiHelpers
2
- include IntrospectiveGrape::CamelSnake
3
2
  def warden
4
3
  env['warden']
5
4
  end
@@ -8,13 +7,13 @@ module ApiHelpers
8
7
  warden.user || params[:api_key].present? && @user = User.find_by_authentication_token(params[:api_key])
9
8
  end
10
9
 
11
- def authorize!
12
- unauthorized! unless current_user
10
+ def authenticate!
11
+ unauthenticated! unless current_user
13
12
  end
14
13
 
15
- # returns an 'unauthorized' response
16
- def unauthorized!(error_type = nil)
17
- respond_error!('unauthorized', error_type, 401)
14
+ # returns an 'unauthenticated' response
15
+ def unauthenticated!(error_type = nil)
16
+ respond_error!('unauthenticated', error_type, 401)
18
17
  end
19
18
 
20
19
  # returns a error response with given type, message_key and status
@@ -1,8 +1,7 @@
1
1
  class Dummy::ChatAPI < DummyAPI
2
- Chat.default_includes :chat
3
2
 
4
3
  before do
5
- authorize!
4
+ authenticate!
6
5
  end
7
6
 
8
7
  resource :chats do
@@ -1,5 +1,20 @@
1
1
  class Dummy::CompanyAPI < IntrospectiveGrape::API
2
- restful Company
2
+ paginate
3
+
4
+ restful Company do
5
+
6
+ desc "Test default values in an extra endpoint"
7
+ params do
8
+ optional :boolean_default, type: Boolean, default: false
9
+ optional :string_default, type: String, default: "foo"
10
+ optional :integer_default, type: Integer, default: 123
11
+ end
12
+ get '/special/list' do
13
+ authorize Company.new, :index?
14
+ present params
15
+ end
16
+
17
+ end
3
18
 
4
19
  class CompanyEntity < Grape::Entity
5
20
  expose :id, :name, :short_name, :created_at, :updated_at
@@ -1,10 +1,10 @@
1
1
  class Dummy::LocationAPI < IntrospectiveGrape::API
2
+ exclude_actions Location, :none
3
+ include_actions LocationBeacon, :index
4
+ include_actions LocationGps, :index
2
5
 
3
6
  default_includes Location, :child_locations, :gps, :beacons, :locatables
4
7
 
5
- exclude_actions LocationBeacon, :show,:create,:update,:destroy
6
- exclude_actions LocationGps, :show,:create,:update,:destroy
7
-
8
8
  restful Location, [:name, :kind,
9
9
  {gps_attributes: [:id, :lat, :lng, :alt, :_destroy]},
10
10
  {beacons_attributes: [:id, :company_id, :mac_address, :uuid, :major, :minor, :_destroy]},
@@ -9,6 +9,7 @@ class Dummy::ProjectAPI < IntrospectiveGrape::API
9
9
  exclude_actions Team, :show
10
10
  exclude_actions TeamUser, :show,:update
11
11
 
12
+ paginate per_page: 2, max_per_page: 10, offset: 2
12
13
 
13
14
  restful Project, [:id, teams_attributes: [:id,:name,:_destroy, team_users_attributes: [:id, :user_id, :_destroy] ]]
14
15
 
@@ -16,15 +16,10 @@ class Dummy::Sessions < Grape::API
16
16
  if user && user.valid_password?(params[:password]) && user.valid_for_authentication?
17
17
 
18
18
  # commented out for now, User model is not yet confirmable
19
- #unauthorized! DummyAPI::USER_NOT_CONFIRMED unless user.confirmed?
19
+ #unauthenticated! DummyAPI::USER_NOT_CONFIRMED unless user.confirmed?
20
20
 
21
21
  token = nil
22
22
  if params[:token]
23
- payload = {
24
- uid: "#{user.id}", # uid must be a string
25
- email: user.email,
26
- avatar_url: user.avatar_url
27
- }
28
23
  user.authentication_token = SecureRandom.urlsafe_base64(nil, false)
29
24
  user.save
30
25
  end
@@ -33,7 +28,7 @@ class Dummy::Sessions < Grape::API
33
28
  env['warden'].set_user(user, scope: :user)
34
29
  present user, with: Dummy::Entities::User, token: token
35
30
  else
36
- unauthorized! DummyAPI::BAD_LOGIN
31
+ unauthenticated! DummyAPI::BAD_LOGIN
37
32
  end
38
33
  end
39
34
 
@@ -43,7 +38,8 @@ class Dummy::Sessions < Grape::API
43
38
  end
44
39
  delete '/' do
45
40
  authorize User.new, :sessions?
46
- if u = User.find_by_authentication_token(params[:api_key])
41
+ u = User.find_by_authentication_token(params[:api_key])
42
+ if u
47
43
  u.authentication_token = nil
48
44
  {status: u.save!}
49
45
  else
@@ -2,10 +2,12 @@ class Dummy::UserAPI < IntrospectiveGrape::API
2
2
 
3
3
  skip_presence_validations :password
4
4
 
5
+ include_actions User, :all
5
6
  exclude_actions Role, :show,:update
6
7
  exclude_actions UserProjectJob, :show,:update
7
8
 
8
9
  restful User, [:id, :email, :password, :first_name, :last_name, :skip_confirmation_email,
10
+ :created_at, :updated_at,
9
11
  user_project_jobs_attributes: [:id, :job_id, :project_id, :_destroy],
10
12
  roles_attributes: [:id, :ownable_type, :ownable_id, :_destroy],
11
13
  avatar_attributes: [:id, :file, :_destroy]
@@ -24,7 +26,7 @@ class Dummy::UserAPI < IntrospectiveGrape::API
24
26
  end
25
27
 
26
28
  class UserEntity < Grape::Entity
27
- expose :id, :email, :first_name, :last_name, :avatar_url
29
+ expose :id, :email, :first_name, :last_name, :avatar_url, :created_at
28
30
  expose :roles, as: :roles_attributes, using: RoleEntity
29
31
  expose :user_project_jobs, as: :user_project_jobs_attributes, using: UserProjectJobEntity
30
32
  end
@@ -1,27 +1,27 @@
1
1
  #require 'grape-swagger'
2
2
  #require 'grape-entity'
3
- require 'active_record_helpers'
4
3
  #require 'introspective_grape/camel_snake'
5
4
 
6
5
  class DummyAPI < Grape::API
7
6
  version 'v1', using: :path
8
- format :json
7
+ format :json
8
+ formatter :json, IntrospectiveGrape::Formatter::CamelJson
9
9
  default_format :json
10
10
 
11
11
  include ErrorHandlers
12
12
  helpers PermissionsHelper
13
13
  helpers ApiHelpers
14
14
 
15
- USER_NOT_CONFIRMED = 'user_not_confirmed' # "Your account must be confirmed, please check your email inbox."
16
- BAD_LOGIN = 'bad_login' # incorrect username or password'
15
+ USER_NOT_CONFIRMED = 'user_not_confirmed'.freeze
16
+ BAD_LOGIN = 'bad_login'.freeze
17
17
 
18
18
  before do
19
19
  # sets server date in response header. This can be used on the client side
20
- header "X-Server-Date", "#{Time.now.to_i}"
20
+ header "X-Server-Date", Time.now.to_i.to_s
21
21
  header "Expires", 1.year.ago.httpdate
22
22
  # Convert incoming camel case params to snake case: grape will totally blow this
23
23
  # if the params hash is not a Hashie::Mash, so make it one of those:
24
- #@params = Hashie::Mash.new(snake_keys(params))
24
+ #@params = Hashie::Mash.new(params.with_snake_keys)
25
25
  end
26
26
 
27
27
  before_validation do
@@ -17,11 +17,11 @@ module ErrorHandlers
17
17
  error_response message: "Join record not found! #{e.message}", status: 404
18
18
  end
19
19
 
20
- m.rescue_from Pundit::NotAuthorizedError do |e|
20
+ m.rescue_from Pundit::NotAuthorizedError do
21
21
  error_response message: "Forbidden", status: 403
22
22
  end
23
23
 
24
- m.rescue_from Pundit::NotDefinedError do |e|
24
+ m.rescue_from Pundit::NotDefinedError do
25
25
  error_response message: "Policy not implemented", status: 501
26
26
  end
27
27
  end
@@ -10,7 +10,7 @@ class ChatUser < AbstractAdapter
10
10
  validate :user_not_already_active, on: :create
11
11
 
12
12
  def user_not_already_active
13
- errors[:base] << "#{user.name} is already present in this chat." if chat.chat_users.where(user_id: user.id, departed_at: nil).count > 0 if user.persisted?
13
+ errors[:base] << "#{user.name} is already present in this chat." if chat.chat_users.where(user_id: user.id, departed_at: nil).count > 0 && user.persisted?
14
14
  end
15
15
 
16
16
  end
@@ -11,10 +11,10 @@ class Image < ActiveRecord::Base
11
11
 
12
12
  #process_in_background :file, processing_image_url: 'empty_avatar.png'
13
13
 
14
- Paperclip.interpolates :imageable_type do |attachment, style|
14
+ Paperclip.interpolates :imageable_type do |attachment, _style|
15
15
  attachment.instance.imageable_type.try(:pluralize)
16
16
  end
17
- Paperclip.interpolates :imageable_id do |attachment, style|
17
+ Paperclip.interpolates :imageable_id do |attachment, _style|
18
18
  attachment.instance.imageable_id
19
19
  end
20
20
 
@@ -15,7 +15,7 @@ class Role < AbstractAdapter
15
15
  ownable_type == 'SuperUser' ? SuperUser.new : super
16
16
  end
17
17
 
18
- def self.ownable_assign_options(model=nil)
18
+ def self.ownable_assign_options(_model=nil)
19
19
  ([SuperUser.new] + Company.all + Project.all).map { |i| [ "#{i.class}: #{i.name}", "#{i.class}-#{i.id}"] }
20
20
  end
21
21
 
@@ -2,15 +2,15 @@ module User::Chatter
2
2
 
3
3
  def message_query(chat_id, new = true)
4
4
  messages.joins(:chat_message_users)
5
- .where('chat_message_users.user_id'=> id)
6
- .where(new ? {'chat_message_users.read_at'=>nil} : '')
7
- .where(chat_id ? {'chat_messages.chat_id'=> chat_id} : '')
8
- .order('') # or it will add an order by id clause that breaks the count query.
5
+ .where('chat_message_users.user_id'=> id)
6
+ .where(new ? {'chat_message_users.read_at'=>nil} : '')
7
+ .where(chat_id ? {'chat_messages.chat_id'=> chat_id} : '')
8
+ .order('') # or it will add an order by id clause that breaks the count query.
9
9
  end
10
10
 
11
11
  def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
12
12
  chat_id = chat.kind_of?(Chat) ? chat.id : chat
13
- new = message_query(chat_id, new = true)
13
+ new = message_query(chat_id)
14
14
  .select("chat_messages.chat_id, count(chat_messages.id) as count")
15
15
  .group('chat_id')
16
16
 
@@ -20,7 +20,7 @@ module User::Chatter
20
20
  def read_messages(chat= nil, mark_as_read= false, new= true)
21
21
  chat_id = chat.kind_of?(Chat) ? chat.id : chat
22
22
  new = message_query(chat_id, new).order('chat_messages.created_at').includes(:author) # :chat?
23
- new.map(&:chat).uniq.each {|chat| mark_as_read(chat) } if mark_as_read
23
+ new.map(&:chat).uniq.each {|c| mark_as_read(c) } if mark_as_read
24
24
  new
25
25
  end
26
26
 
@@ -5,9 +5,9 @@ class UserProjectJob < AbstractAdapter
5
5
 
6
6
  validates_inclusion_of :job, in: proc {|r| r.project.try(:jobs) || [] }
7
7
 
8
- delegate :email, :avatar_url, to: :user
9
- delegate :title, to: :job
10
- delegate :name, to: :project
8
+ delegate :email, :avatar_url, to: :user, allow_nil: true
9
+ delegate :title, to: :job, allow_nil: true
10
+ delegate :name, to: :project, allow_nil: true
11
11
 
12
12
  def self.options_for_job(project=nil)
13
13
  project.jobs
@@ -5,7 +5,7 @@ require "active_record/railtie"
5
5
  require "action_controller/railtie"
6
6
  require "action_mailer/railtie"
7
7
  require "action_view/railtie"
8
- require "sprockets/railtie"
8
+ #require "sprockets/railtie"
9
9
  require 'activerecord-tableless'
10
10
  require 'devise'
11
11
  require 'devise/async'
@@ -4,10 +4,10 @@ class CreateImages < ActiveRecord::Migration
4
4
  t.references :imageable, polymorphic: true, index: true
5
5
  t.attachment :file
6
6
  t.boolean :file_processing, null: false, default: false
7
- t.json :meta
7
+ t.json :meta
8
8
  t.string :source
9
- t.float :lat
10
- t.float :lng
9
+ t.float :lat
10
+ t.float :lng
11
11
  t.timestamp :taken_at
12
12
  t.timestamps null: false
13
13
  end
@@ -102,7 +102,7 @@ ActiveRecord::Schema.define(version: 20150909225019) do
102
102
  t.integer "file_file_size"
103
103
  t.datetime "file_updated_at"
104
104
  t.boolean "file_processing", default: false, null: false
105
- t.text "meta"
105
+ t.text "meta"
106
106
  t.string "source"
107
107
  t.float "lat"
108
108
  t.float "lng"
@@ -6,7 +6,7 @@ RSpec.describe Image, type: :model do
6
6
 
7
7
  it { should have_attached_file(:file) }
8
8
  it { should validate_attachment_content_type(:file).
9
- allowing('image/png', 'image/gif', 'image/jpeg')
9
+ allowing('image/png', 'image/gif', 'image/jpeg')
10
10
  }
11
11
  it { should validate_attachment_size(:file).less_than(2.megabytes) }
12
12
 
@@ -25,35 +25,35 @@ RSpec.describe Role, type: :model do
25
25
  context "User helper methods" do
26
26
  it "should register a user as a super user" do
27
27
  user.superuser?.should == false
28
- ur = Role.create!(user:user, ownable: SuperUser.new)
28
+ Role.create!(user:user, ownable: SuperUser.new)
29
29
  user.reload
30
30
  user.superuser?.should == true
31
31
  end
32
32
 
33
33
  it "should register a company admin" do
34
34
  user.admin?(company).should == false
35
- ur = Role.create!(user:user, ownable: company)
35
+ Role.create!(user:user, ownable: company)
36
36
  user.reload
37
37
  user.admin?(company).should == true
38
38
  end
39
39
 
40
40
  it "should register a project administrator" do
41
41
  user.admin?(project).should == false
42
- ur = Role.create!(user:user, ownable: project)
42
+ Role.create!(user:user, ownable: project)
43
43
  user.reload
44
44
  user.admin?(project).should == true
45
45
  end
46
46
 
47
47
  it "should register a user a company admin if admin of any company" do
48
48
  user.company_admin?.should == false
49
- ur = Role.create!(user:user, ownable: company)
49
+ Role.create!(user:user, ownable: company)
50
50
  user.reload
51
51
  user.company_admin?.should == true
52
52
  end
53
53
 
54
54
  it "should register a user as a project admin if admin of any project" do
55
55
  user.project_admin?.should == false
56
- ur = Role.create!(user:user, ownable: project)
56
+ Role.create!(user:user, ownable: project)
57
57
  user.reload
58
58
  user.project_admin?.should == true
59
59
  end
@@ -16,7 +16,7 @@ RSpec.describe UserLocation, type: :model do
16
16
 
17
17
  it "logs a user's locations by beacon" do
18
18
  beacon = LocationBeacon.last
19
- p1 = user.user_locations.build(location: beacon.location, detectable: beacon, coords: rand_coords)
19
+ user.user_locations.build(location: beacon.location, detectable: beacon, coords: rand_coords)
20
20
  user.save.should == true
21
21
  p2 = user.user_locations.build(location: beacon.location, detectable: beacon, coords: rand_coords)
22
22
  user.save.should == true
@@ -25,7 +25,7 @@ RSpec.describe UserLocation, type: :model do
25
25
 
26
26
  it "logs a user's beacon location by gps" do
27
27
  gps = LocationGps.last
28
- p1 = user.user_locations.build(location: gps.location, detectable: gps, coords: rand_coords)
28
+ user.user_locations.build(location: gps.location, detectable: gps, coords: rand_coords)
29
29
  user.save.should == true
30
30
  p2 = user.user_locations.build(location: gps.location, detectable: gps, coords: rand_coords)
31
31
  user.save.should == true
@@ -22,7 +22,7 @@ RSpec.describe UserProjectJob, type: :model do
22
22
  j = Job.make!
23
23
  p.jobs.push j
24
24
  p.save
25
- r = UserProjectJob.make!(project: p, job: j)
25
+ UserProjectJob.make!(project: p, job: j)
26
26
  UserProjectJob.options_for_job(p).should == p.jobs
27
27
  end
28
28
 
data/spec/rails_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
- ENV["RAILS_ENV"] ||= 'test'
1
+ require 'coveralls'
2
+ Coveralls.wear!('rails')
3
+ ENV["RAILS_ENV"] = 'test'
2
4
  require File.expand_path("../dummy/config/environment", __FILE__)
3
5
  require 'rspec/rails'
4
6
  require 'support/request_helpers'