introspective_grape 0.6.1 → 0.7.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +85 -84
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +10 -0
  5. data/Gemfile +38 -22
  6. data/README.md +13 -20
  7. data/introspective_grape.gemspec +41 -64
  8. data/lib/introspective_grape/api.rb +469 -461
  9. data/lib/introspective_grape/camel_snake.rb +3 -3
  10. data/lib/introspective_grape/create_helpers.rb +25 -25
  11. data/lib/introspective_grape/filters.rb +5 -3
  12. data/lib/introspective_grape/route.rb +11 -0
  13. data/lib/introspective_grape/traversal.rb +56 -56
  14. data/lib/introspective_grape/validators.rb +37 -36
  15. data/lib/introspective_grape/version.rb +5 -5
  16. data/lib/introspective_grape.rb +1 -0
  17. data/spec/dummy/Gemfile +24 -23
  18. data/spec/dummy/app/api/{api_helpers.rb → authentication_helper.rb} +38 -38
  19. data/spec/dummy/app/api/dummy/chat_api.rb +1 -1
  20. data/spec/dummy/app/api/dummy/company_api.rb +1 -1
  21. data/spec/dummy/app/api/dummy/location_api.rb +1 -1
  22. data/spec/dummy/app/api/dummy/project_api.rb +2 -2
  23. data/spec/dummy/app/api/dummy/role_api.rb +1 -1
  24. data/spec/dummy/app/api/dummy/sessions.rb +2 -2
  25. data/spec/dummy/app/api/dummy/user_api.rb +1 -1
  26. data/spec/dummy/app/api/dummy_api.rb +60 -61
  27. data/spec/dummy/app/api/error_handlers.rb +6 -6
  28. data/spec/dummy/app/api/permissions_helper.rb +7 -7
  29. data/spec/dummy/app/helpers/current.rb +3 -3
  30. data/spec/dummy/app/models/abstract_adapter.rb +11 -8
  31. data/spec/dummy/app/models/chat_message.rb +34 -34
  32. data/spec/dummy/app/models/chat_user.rb +16 -16
  33. data/spec/dummy/app/models/company.rb +3 -2
  34. data/spec/dummy/app/models/location.rb +26 -26
  35. data/spec/dummy/app/models/role.rb +30 -30
  36. data/spec/dummy/app/models/team.rb +14 -14
  37. data/spec/dummy/app/models/user/chatter.rb +79 -79
  38. data/spec/dummy/app/models/user.rb +2 -0
  39. data/spec/dummy/bin/bundle +3 -3
  40. data/spec/dummy/bin/rails +4 -4
  41. data/spec/dummy/bin/setup +36 -36
  42. data/spec/dummy/bin/update +31 -31
  43. data/spec/dummy/bin/yarn +11 -11
  44. data/spec/dummy/config/application.rb +30 -30
  45. data/spec/dummy/config/boot.rb +3 -3
  46. data/spec/dummy/config/environment.rb +5 -5
  47. data/spec/dummy/config/environments/development.rb +54 -54
  48. data/spec/dummy/config/environments/production.rb +81 -81
  49. data/spec/dummy/config/environments/test.rb +47 -47
  50. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -8
  51. data/spec/dummy/config/initializers/assets.rb +14 -14
  52. data/spec/dummy/config/initializers/content_security_policy.rb +25 -25
  53. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -5
  54. data/spec/dummy/config/initializers/new_framework_defaults_5_2.rb +38 -38
  55. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  56. data/spec/dummy/config/locales/en.yml +33 -33
  57. data/spec/dummy/config/routes.rb +1 -1
  58. data/spec/dummy/config/storage.yml +34 -34
  59. data/spec/models/image_spec.rb +10 -10
  60. data/spec/rails_helper.rb +1 -2
  61. data/spec/requests/chat_api_spec.rb +1 -1
  62. data/spec/requests/company_api_spec.rb +1 -1
  63. data/spec/requests/location_api_spec.rb +1 -1
  64. data/spec/requests/project_api_spec.rb +185 -185
  65. data/spec/requests/role_api_spec.rb +1 -1
  66. data/spec/requests/user_api_spec.rb +221 -221
  67. data/spec/support/request_helpers.rb +22 -22
  68. metadata +9 -192
  69. data/spec/dummy/.ruby-version +0 -1
  70. data/spec/dummy/config/initializers/inflections.rb +0 -16
@@ -2,27 +2,27 @@ require 'pundit'
2
2
  module ErrorHandlers
3
3
  def self.included(m)
4
4
  m.rescue_from ActiveRecord::RecordInvalid do |e|
5
- error_response message: e.record.errors.to_a.uniq.join(', '), status: 400
5
+ error! e.record.errors.to_a.uniq.join(', '), 400
6
6
  end
7
7
 
8
8
  m.rescue_from Grape::Exceptions::ValidationErrors do |e|
9
- error_response message: e.message, status: 400
9
+ error! e.message, 400
10
10
  end
11
11
 
12
12
  m.rescue_from ActiveRecord::RecordNotFound do |e|
13
- error_response message: "Record not found! #{e.message}", status: 404
13
+ error! "Record not found! #{e.message}", 404
14
14
  end
15
15
 
16
16
  m.rescue_from ActiveRecord::InvalidForeignKey do |e|
17
- error_response message: "Join record not found! #{e.message}", status: 404
17
+ error! "Join record not found! #{e.message}", 404
18
18
  end
19
19
 
20
20
  m.rescue_from Pundit::NotAuthorizedError do
21
- error_response message: "Forbidden", status: 403
21
+ error! "Forbidden", 403
22
22
  end
23
23
 
24
24
  m.rescue_from Pundit::NotDefinedError do
25
- error_response message: "Policy not implemented", status: 501
25
+ error! "Policy not implemented", 501
26
26
  end
27
27
  end
28
28
  end
@@ -1,7 +1,7 @@
1
- require 'pundit'
2
- module PermissionsHelper
3
- # Pundit won't import it's methods unless it sees a stub of ActionController's hide_action.
4
- def hide_action; end
5
- include Pundit::Authorization
6
-
7
- end
1
+ require 'pundit'
2
+ module PermissionsHelper
3
+ # Pundit won't import it's methods unless it sees a stub of ActionController's hide_action.
4
+ def hide_action; end
5
+ include Pundit::Authorization
6
+
7
+ end
@@ -1,3 +1,3 @@
1
- module Current
2
- thread_mattr_accessor :user
3
- end
1
+ module Current
2
+ thread_mattr_accessor :user
3
+ end
@@ -1,13 +1,16 @@
1
1
  class AbstractAdapter < ActiveRecord::Base
2
- self.abstract_class = true
2
+ primary_abstract_class
3
3
 
4
- class << self
5
- def human_attribute_name(attr, options = {})
6
- # The default formatting of validation errors sucks, this helps a little syntatically:
7
- super.titleize+":"
8
- end
9
-
10
- end
4
+ class << self
5
+ def inherited(klass)
6
+ super
7
+ klass.validates_by_schema
8
+ end
11
9
 
10
+ def human_attribute_name(attr, options = {})
11
+ # The default formatting of validation errors sucks, this helps a little syntatically:
12
+ super.titleize+":"
13
+ end
14
+ end
12
15
  end
13
16
 
@@ -1,34 +1,34 @@
1
- class ChatMessage < AbstractAdapter
2
- belongs_to :chat
3
- belongs_to :author, class_name: 'User'
4
-
5
- has_many :chat_users, through: :chat
6
- has_many :recipients, lambda {|message| where(':created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR :created_at <= chat_users.departed_at)', created_at: message.created_at ) }, through: :chat_users, source: :user, class_name: 'User'
7
-
8
- # Create ChatUserMessage records for each recipient to track read status
9
- has_many :chat_message_users, dependent: :destroy
10
-
11
- validate :author_in_chat
12
-
13
- def author_in_chat
14
- errors.add(:base, 'User not in chat session.') unless chat.active_users.include? author
15
- end
16
-
17
- before_save :create_message_users, if: :new_record?
18
- def create_message_users
19
- chat_users.merge(ChatUser.current).each do |cu|
20
- chat_message_users.build(user: cu.user)
21
- end
22
- end
23
-
24
- def read_by?(user)
25
- chat_message_users.merge(ChatMessageUser.read).map(&:user_id).include?(user.id)
26
- end
27
-
28
- def self.find_chat_for_users(users)
29
- # presumably much more efficient ways to run an intersecton, we want to find the last
30
- # exact match with the users being messaged to append to the existing chat.
31
- Chat.eager_load(:chat_users).where("chat_users.departed_at IS NULL").order('chats.created_at desc').detect {|c| c.chat_users.map(&:user_id).uniq.sort == users.map(&:id).sort }
32
- end
33
-
34
- end
1
+ class ChatMessage < AbstractAdapter
2
+ belongs_to :chat
3
+ belongs_to :author, class_name: 'User'
4
+
5
+ has_many :chat_users, through: :chat
6
+ has_many :recipients, lambda {|message| where(':created_at >= chat_users.created_at and (chat_users.departed_at IS NULL OR :created_at <= chat_users.departed_at)', created_at: message.created_at ) }, through: :chat_users, source: :user, class_name: 'User'
7
+
8
+ # Create ChatUserMessage records for each recipient to track read status
9
+ has_many :chat_message_users, dependent: :destroy
10
+
11
+ validate :author_in_chat
12
+
13
+ def author_in_chat
14
+ errors.add(:base, 'User not in chat session.') unless chat.active_users.include? author
15
+ end
16
+
17
+ before_save :create_message_users, if: :new_record?
18
+ def create_message_users
19
+ chat_users.merge(ChatUser.current).each do |cu|
20
+ chat_message_users.build(user: cu.user)
21
+ end
22
+ end
23
+
24
+ def read_by?(user)
25
+ chat_message_users.merge(ChatMessageUser.read).map(&:user_id).include?(user.id)
26
+ end
27
+
28
+ def self.find_chat_for_users(users)
29
+ # presumably much more efficient ways to run an intersecton, we want to find the last
30
+ # exact match with the users being messaged to append to the existing chat.
31
+ Chat.eager_load(:chat_users).where("chat_users.departed_at IS NULL").order('chats.created_at desc').detect {|c| c.chat_users.map(&:user_id).uniq.sort == users.map(&:id).sort }
32
+ end
33
+
34
+ end
@@ -1,16 +1,16 @@
1
- class ChatUser < AbstractAdapter
2
- belongs_to :chat
3
- belongs_to :user
4
-
5
- alias_attribute :joined_at, :created_at
6
- alias_attribute :left_at, :departed_at
7
-
8
- scope :current, ->{ where(departed_at: nil) }
9
-
10
- validate :user_not_already_active, on: :create
11
-
12
- def user_not_already_active
13
- errors.add(: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
- end
15
-
16
- end
1
+ class ChatUser < AbstractAdapter
2
+ belongs_to :chat
3
+ belongs_to :user
4
+
5
+ alias_attribute :joined_at, :created_at
6
+ alias_attribute :left_at, :departed_at
7
+
8
+ scope :current, ->{ where(departed_at: nil) }
9
+
10
+ validate :user_not_already_active, on: :create
11
+
12
+ def user_not_already_active
13
+ errors.add(: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
+ end
15
+
16
+ end
@@ -9,8 +9,9 @@ class Company < AbstractAdapter
9
9
 
10
10
  has_many :projects, foreign_key: :owner_id, dependent: :destroy, inverse_of: :owner
11
11
 
12
- validates_length_of :name, maximum: 256
13
- validates_length_of :short_name, maximum: 10
12
+ # leave these to validates_by_schema:
13
+ # validates_length_of :name, maximum: 256
14
+ # validates_length_of :short_name, maximum: 10
14
15
 
15
16
  def self.grape_validations
16
17
  {
@@ -1,26 +1,26 @@
1
- class Location < AbstractAdapter
2
- has_many :locatables, dependent: :destroy
3
- has_many :companies, through: :locatables, source: :locatable, source_type: 'Company'
4
-
5
- has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
6
- has_one :gps, class_name: 'LocationGps', dependent: :destroy
7
- delegate :lat,:lng,:alt, to: :gps
8
-
9
- belongs_to :parent_location, foreign_key: :parent_location_id, class_name: 'Location', inverse_of: :child_locations, optional: true
10
- has_many :child_locations, foreign_key: :parent_location_id, class_name: 'Location', dependent: :destroy, inverse_of: :parent_location
11
-
12
- has_many :user_locations, dependent: :destroy
13
-
14
- # isn't this list going to be kinda long? are there any reasonable constraints to put
15
- # on this random bit of metadata?
16
- validates_inclusion_of :kind, in: %w(airport terminal gate plane)
17
-
18
- accepts_nested_attributes_for :child_locations, allow_destroy: true
19
- accepts_nested_attributes_for :gps, allow_destroy: true
20
- accepts_nested_attributes_for :beacons, allow_destroy: true
21
-
22
- def coords
23
- [gps.lat, gps.lng, gps.alt]
24
- end
25
-
26
- end
1
+ class Location < AbstractAdapter
2
+ has_many :locatables, dependent: :destroy
3
+ has_many :companies, through: :locatables, source: :locatable, source_type: 'Company'
4
+
5
+ has_many :beacons, class_name: 'LocationBeacon', dependent: :destroy
6
+ has_one :gps, class_name: 'LocationGps', dependent: :destroy
7
+ delegate :lat,:lng,:alt, to: :gps
8
+
9
+ belongs_to :parent_location, foreign_key: :parent_location_id, class_name: 'Location', inverse_of: :child_locations, optional: true
10
+ has_many :child_locations, foreign_key: :parent_location_id, class_name: 'Location', dependent: :destroy, inverse_of: :parent_location
11
+
12
+ has_many :user_locations, dependent: :destroy
13
+
14
+ # isn't this list going to be kinda long? are there any reasonable constraints to put
15
+ # on this random bit of metadata?
16
+ validates_inclusion_of :kind, in: %w(airport terminal gate plane)
17
+
18
+ accepts_nested_attributes_for :child_locations, allow_destroy: true
19
+ accepts_nested_attributes_for :gps, allow_destroy: true
20
+ accepts_nested_attributes_for :beacons, allow_destroy: true
21
+
22
+ def coords
23
+ [gps.lat, gps.lng, gps.alt]
24
+ end
25
+
26
+ end
@@ -1,30 +1,30 @@
1
- class Role < AbstractAdapter
2
- belongs_to :user
3
- belongs_to :ownable, polymorphic: true, optional: true
4
-
5
- validates_uniqueness_of :user_id, scope: [:ownable_type,:ownable_id], unless: Proc.new {|u| u.user_id.nil? }, message: "user has already been assigned that role"
6
- OWNABLE_TYPES = %w(Company Project).freeze
7
- validates_inclusion_of :ownable_type, in: OWNABLE_TYPES
8
-
9
- delegate :email, to: :user, allow_nil: true
10
- def attributes
11
- super.merge(email: email)
12
- end
13
-
14
- def self.grape_validations
15
- { ownable_type: { values: OWNABLE_TYPES } }
16
- end
17
-
18
- def self.ownable_assign_options(_model=nil)
19
- (Company.all + Project.all).map { |i| [ "#{i.class}: #{i.name}", "#{i.class}-#{i.id}"] }
20
- end
21
-
22
- def ownable_assign
23
- ownable.present? ? "#{ownable_type}-#{ownable_id}" : nil
24
- end
25
-
26
- def ownable_assign=(value)
27
- self.ownable_type,self.ownable_id = value.split('-')
28
- end
29
-
30
- end
1
+ class Role < AbstractAdapter
2
+ belongs_to :user
3
+ belongs_to :ownable, polymorphic: true, optional: true
4
+
5
+ validates_uniqueness_of :user_id, scope: [:ownable_type,:ownable_id], unless: Proc.new {|u| u.user_id.nil? }, message: "user has already been assigned that role"
6
+ OWNABLE_TYPES = %w(Company Project).freeze
7
+ validates_inclusion_of :ownable_type, in: OWNABLE_TYPES
8
+
9
+ delegate :email, to: :user, allow_nil: true
10
+ def attributes
11
+ super.merge(email: email)
12
+ end
13
+
14
+ def self.grape_validations
15
+ { ownable_type: { values: OWNABLE_TYPES } }
16
+ end
17
+
18
+ def self.ownable_assign_options(_model=nil)
19
+ (Company.all + Project.all).map { |i| [ "#{i.class}: #{i.name}", "#{i.class}-#{i.id}"] }
20
+ end
21
+
22
+ def ownable_assign
23
+ ownable.present? ? "#{ownable_type}-#{ownable_id}" : nil
24
+ end
25
+
26
+ def ownable_assign=(value)
27
+ self.ownable_type,self.ownable_id = value.split('-')
28
+ end
29
+
30
+ end
@@ -1,14 +1,14 @@
1
- class Team < AbstractAdapter
2
- belongs_to :project
3
- belongs_to :creator, class_name: 'User'
4
-
5
- has_many :team_users, inverse_of: :team
6
- has_many :users, through: :team_users
7
- accepts_nested_attributes_for :team_users, allow_destroy: true
8
-
9
- before_validation :set_creator
10
-
11
- def set_creator
12
- self.creator ||= Current.user
13
- end
14
- end
1
+ class Team < AbstractAdapter
2
+ belongs_to :project
3
+ belongs_to :creator, class_name: 'User'
4
+
5
+ has_many :team_users, inverse_of: :team
6
+ has_many :users, through: :team_users
7
+ accepts_nested_attributes_for :team_users, allow_destroy: true
8
+
9
+ before_validation :set_creator
10
+
11
+ def set_creator
12
+ self.creator ||= Current.user
13
+ end
14
+ end
@@ -1,79 +1,79 @@
1
- module User::Chatter
2
-
3
- def message_query(chat_id, new = true)
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.
9
- end
10
-
11
- def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
12
- chat_id = chat.kind_of?(Chat) ? chat.id : chat
13
- new = message_query(chat_id)
14
- .select("chat_messages.chat_id, count(chat_messages.id) as count")
15
- .group('chat_id')
16
-
17
- chat ? { chat_id => new.first.try(:count)||0 } : Hash[new.map {|c| [c.chat_id, c.count]} ]
18
- end
19
-
20
- def read_messages(chat= nil, mark_as_read= false, new= true)
21
- chat_id = chat.kind_of?(Chat) ? chat.id : chat
22
- new = message_query(chat_id, new).order('chat_messages.created_at').includes(:author) # :chat?
23
- new.map(&:chat).uniq.each {|c| mark_as_read(c) } if mark_as_read
24
- new
25
- end
26
-
27
- def chat(users, message)
28
- users = [users].flatten
29
- users = users.first.kind_of?(User) ? users : User.where(id: users)
30
- chat = Chat.create(creator: self)
31
- chat.users.push users
32
- chat.messages.build(message: message, author: self)
33
- chat.save!
34
- chat
35
- end
36
-
37
- def reply(chat, message)
38
- chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
39
- mark_as_read(chat) # a reply implies that the thread has been read
40
- chat.messages.build(message: message, author: self)
41
- chat.save!
42
- chat
43
- end
44
-
45
- def add_chatters(chat, users)
46
- users = [users].flatten
47
- users = users.first.kind_of?(User) ? users : User.where(id: users)
48
- chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
49
-
50
- if chat.active_users.include?(self) # only current participants can add new users
51
- chat.users.push users
52
- chat.messages.build(chat: chat, author: self, message: "#{self.name} [[ADDED_USER_MESSAGE]] #{users.map(&:name).join(',')}")
53
- chat.save!
54
- else
55
- chat.errors.add(:base, "Only current chat participants can add users.")
56
- raise ActiveRecord::RecordInvalid.new(chat)
57
- end
58
- end
59
-
60
- def leave_chat(chat)
61
- chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
62
-
63
- if chat.active_users.include?(self)
64
- reply(chat, "#{name} [[DEPARTS_MESSAGE]]")
65
- chat.chat_users.detect {|cu| cu.user_id == self.id}.update(departed_at: Time.now)
66
- else
67
- true
68
- end
69
- end
70
-
71
- def mark_as_read(chat)
72
- ChatMessageUser.joins(:chat_message).where('read_at IS NULL AND chat_messages.chat_id = ? AND user_id = ?', chat.id, id).update_all(read_at: Time.now)
73
- end
74
-
75
- def mark_messages_as_read(messages)
76
- chat_message_users.where("chat_message_id in (?) and read_at IS NULL", messages.map(&:id)).update_all(read_at: Time.now)
77
- end
78
-
79
- end
1
+ module User::Chatter
2
+
3
+ def message_query(chat_id, new = true)
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.
9
+ end
10
+
11
+ def new_messages?(chat=nil) # returns a hash of chat_ids with new message counts
12
+ chat_id = chat.kind_of?(Chat) ? chat.id : chat
13
+ new = message_query(chat_id)
14
+ .select("chat_messages.chat_id, count(chat_messages.id) as count")
15
+ .group('chat_id')
16
+
17
+ chat ? { chat_id => new.first.try(:count)||0 } : Hash[new.map {|c| [c.chat_id, c.count]} ]
18
+ end
19
+
20
+ def read_messages(chat= nil, mark_as_read= false, new= true)
21
+ chat_id = chat.kind_of?(Chat) ? chat.id : chat
22
+ new = message_query(chat_id, new).order('chat_messages.created_at').includes(:author) # :chat?
23
+ new.map(&:chat).uniq.each {|c| mark_as_read(c) } if mark_as_read
24
+ new
25
+ end
26
+
27
+ def chat(users, message)
28
+ users = [users].flatten
29
+ users = users.first.kind_of?(User) ? users : User.where(id: users)
30
+ chat = Chat.create(creator: self)
31
+ chat.users.push users
32
+ chat.messages.build(message: message, author: self)
33
+ chat.save!
34
+ chat
35
+ end
36
+
37
+ def reply(chat, message)
38
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
39
+ mark_as_read(chat) # a reply implies that the thread has been read
40
+ chat.messages.build(message: message, author: self)
41
+ chat.save!
42
+ chat
43
+ end
44
+
45
+ def add_chatters(chat, users)
46
+ users = [users].flatten
47
+ users = users.first.kind_of?(User) ? users : User.where(id: users)
48
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
49
+
50
+ if chat.active_users.include?(self) # only current participants can add new users
51
+ chat.users.push users
52
+ chat.messages.build(chat: chat, author: self, message: "#{self.name} [[ADDED_USER_MESSAGE]] #{users.map(&:name).join(',')}")
53
+ chat.save!
54
+ else
55
+ chat.errors.add(:base, "Only current chat participants can add users.")
56
+ raise ActiveRecord::RecordInvalid.new(chat)
57
+ end
58
+ end
59
+
60
+ def leave_chat(chat)
61
+ chat = chat.kind_of?(Chat) ? chat : Chat.find(chat)
62
+
63
+ if chat.active_users.include?(self)
64
+ reply(chat, "#{name} [[DEPARTS_MESSAGE]]")
65
+ chat.chat_users.detect {|cu| cu.user_id == self.id}.update(departed_at: Time.now)
66
+ else
67
+ true
68
+ end
69
+ end
70
+
71
+ def mark_as_read(chat)
72
+ ChatMessageUser.joins(:chat_message).where('read_at IS NULL AND chat_messages.chat_id = ? AND user_id = ?', chat.id, id).update_all(read_at: Time.now)
73
+ end
74
+
75
+ def mark_messages_as_read(messages)
76
+ chat_message_users.where("chat_message_id in (?) and read_at IS NULL", messages.map(&:id)).update_all(read_at: Time.now)
77
+ end
78
+
79
+ end
@@ -5,6 +5,8 @@ class User < AbstractAdapter
5
5
  devise :database_authenticatable, :registerable, :confirmable,
6
6
  :recoverable, :rememberable, :trackable, :validatable, :lockable
7
7
 
8
+ validates_by_schema except: :encrypted_password
9
+
8
10
  scope :active, -> { where(:locked_at => nil) }
9
11
  scope :inactive, -> { where('locked_at is not null') }
10
12
 
@@ -1,3 +1,3 @@
1
- #!/usr/bin/env ruby
2
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3
- load Gem.bin_path('bundler', 'bundle')
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3
+ load Gem.bin_path('bundler', 'bundle')
data/spec/dummy/bin/rails CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
2
- APP_PATH = File.expand_path('../config/application', __dir__)
3
- require_relative '../config/boot'
4
- require 'rails/commands'
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
data/spec/dummy/bin/setup CHANGED
@@ -1,36 +1,36 @@
1
- #!/usr/bin/env ruby
2
- require 'fileutils'
3
- include FileUtils
4
-
5
- # path to your application root.
6
- APP_ROOT = File.expand_path('..', __dir__)
7
-
8
- def system!(*args)
9
- system(*args) || abort("\n== Command #{args} failed ==")
10
- end
11
-
12
- chdir APP_ROOT do
13
- # This script is a starting point to setup your application.
14
- # Add necessary setup steps to this file.
15
-
16
- puts '== Installing dependencies =='
17
- system! 'gem install bundler --conservative'
18
- system('bundle check') || system!('bundle install')
19
-
20
- # Install JavaScript dependencies if using Yarn
21
- # system('bin/yarn')
22
-
23
- # puts "\n== Copying sample files =="
24
- # unless File.exist?('config/database.yml')
25
- # cp 'config/database.yml.sample', 'config/database.yml'
26
- # end
27
-
28
- puts "\n== Preparing database =="
29
- system! 'bin/rails db:setup'
30
-
31
- puts "\n== Removing old logs and tempfiles =="
32
- system! 'bin/rails log:clear tmp:clear'
33
-
34
- puts "\n== Restarting application server =="
35
- system! 'bin/rails restart'
36
- end
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ include FileUtils
4
+
5
+ # path to your application root.
6
+ APP_ROOT = File.expand_path('..', __dir__)
7
+
8
+ def system!(*args)
9
+ system(*args) || abort("\n== Command #{args} failed ==")
10
+ end
11
+
12
+ chdir APP_ROOT do
13
+ # This script is a starting point to setup your application.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts '== Installing dependencies =='
17
+ system! 'gem install bundler --conservative'
18
+ system('bundle check') || system!('bundle install')
19
+
20
+ # Install JavaScript dependencies if using Yarn
21
+ # system('bin/yarn')
22
+
23
+ # puts "\n== Copying sample files =="
24
+ # unless File.exist?('config/database.yml')
25
+ # cp 'config/database.yml.sample', 'config/database.yml'
26
+ # end
27
+
28
+ puts "\n== Preparing database =="
29
+ system! 'bin/rails db:setup'
30
+
31
+ puts "\n== Removing old logs and tempfiles =="
32
+ system! 'bin/rails log:clear tmp:clear'
33
+
34
+ puts "\n== Restarting application server =="
35
+ system! 'bin/rails restart'
36
+ end