• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

simukappu / activity_notification / 12735624472

12 Jan 2025 05:24PM UTC coverage: 100.0%. Remained the same
12735624472

push

travis-ci

simukappu
Update Ruby versions for test

3432 of 3432 relevant lines covered (100.0%)

2130.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/lib/activity_notification/renderable.rb
1
module ActivityNotification
24✔
2
  # Provides logic for rendering notifications.
3
  # Handles both i18n strings support and smart partials rendering (different templates per the notification key).
4
  # This module deeply uses PublicActivity gem as reference.
5
  module Renderable
24✔
6
    # Virtual attribute returning text description of the notification
7
    # using the notification's key to translate using i18n.
8
    #
9
    # @param [Hash] params Parameters for rendering notification text
10
    # @option params [String] :target Target type name to use as i18n text key
11
    # @option params [Hash] others Parameters to be referred in i18n text
12
    # @return [String] Rendered text
13
    def text(params = {})
24✔
14
      k = key.split('.')
5,112✔
15
      k.unshift('notification') if k.first != 'notification'
5,112✔
16
      if params.has_key?(:target)
5,112✔
17
        k.insert(1, params[:target])
24✔
18
      else
19
        k.insert(1, target.to_resource_name)
5,088✔
20
      end
21
      k.push('text')
5,112✔
22
      k = k.join('.')
5,112✔
23

24
      attrs = (parameters.symbolize_keys.merge(params) || {}).merge(
5,112✔
25
        group_member_count:          group_member_count,
26
        group_notification_count:    group_notification_count,
27
        group_member_notifier_count: group_member_notifier_count,
28
        group_notifier_count:        group_notifier_count
29
      )
30

31
      # Generate the :default fallback key without using pluralization key :count
32
      default = I18n.t(k, **attrs)
5,112✔
33
      I18n.t(k, **attrs.merge(count: group_notification_count, default: default))
5,088✔
34
    end
35

36
    # Renders notification from views.
37
    #
38
    # The preferred way of rendering notifications is
39
    # to provide a template specifying how the rendering should be happening.
40
    # However, you can choose using _i18n_ based approach when developing
41
    # an application that supports plenty of languages.
42
    #
43
    # If partial view exists that matches the "target" type and "key" attribute
44
    # renders that partial with local variables set to contain both
45
    # Notification and notification_parameters (hash with indifferent access).
46
    #
47
    # If the partial view does not exist and you wish to fallback to rendering
48
    # through the i18n translation, you can do so by passing in a :fallback
49
    # parameter whose value equals :text.
50
    #
51
    # If you do not want to define a partial view, and instead want to have
52
    # all missing views fallback to a default, you can define the :fallback
53
    # value equal to the partial you wish to use when the partial defined
54
    # by the notification key does not exist.
55
    #
56
    # Render a list of all notifications of @target from a view (erb):
57
    #   <ul>
58
    #     <% @target.notifications.each do |notification|  %>
59
    #       <li><%= render_notification notification %></li>
60
    #     <% end %>
61
    #   </ul>
62
    #
63
    # Fallback to the i18n text translation if the view is missing:
64
    #   <ul>
65
    #     <% @target.notifications.each do |notification|  %>
66
    #       <li><%= render_notification notification, fallback: :text %></li>
67
    #     <% end %>
68
    #   </ul>
69
    #
70
    # Fallback to a default view if the view for the current notification key is missing:
71
    #   <ul>
72
    #     <% @target.notifications.each do |notification|  %>
73
    #       <li><%= render_notification notification, fallback: 'default' %></li>
74
    #     <% end %>
75
    #   </ul>
76
    #
77
    # = Layouts
78
    #
79
    # You can supply a layout that will be used for notification partials
80
    # with :layout param.
81
    # Keep in mind that layouts for partials are also partials.
82
    #
83
    # Supply a layout:
84
    #   # in views:
85
    #   # All examples look for a layout in app/views/layouts/_notification.erb
86
    #   render_notification @notification, layout: "notification"
87
    #   render_notification @notification, layout: "layouts/notification"
88
    #   render_notification @notification, layout: :notification
89
    #
90
    #   # app/views/layouts/_notification.erb
91
    #   <p><%= notification.created_at %></p>
92
    #   <%= yield %>
93
    #
94
    # == Custom Layout Location
95
    #
96
    # You can customize the layout directory by supplying :layout_root
97
    # or by using an absolute path.
98
    #
99
    # Declare custom layout location:
100
    #   # Both examples look for a layout in "app/views/custom/_layout.erb"
101
    #   render_notification @notification, layout_root: "custom"
102
    #   render_notification @notification, layout: "/custom/layout"
103
    #
104
    # = Creating a template
105
    #
106
    # To use templates for formatting how the notification should render,
107
    # create a template based on target type and notification key, for example:
108
    #
109
    # Given a target type users and key _notification.article.create_, create directory tree
110
    # _app/views/activity_notification/notifications/users/article/_ and create the _create_ partial there
111
    #
112
    # Note that if a key consists of more than three parts splitted by commas, your
113
    # directory structure will have to be deeper, for example:
114
    #   notification.article.comment.reply => app/views/activity_notification/notifications/users/article/comment/_reply.html.erb
115
    #
116
    # == Custom Directory
117
    #
118
    # You can override the default `activity_notification/notifications/#{target}` template root with the :partial_root parameter.
119
    #
120
    # Custom template root:
121
    #    # look for templates inside of /app/views/custom instead of /app/views/public_directory/activity_notification/notifications/#{target}
122
    #    render_notification @notification, partial_root: "custom"
123
    #
124
    # == Variables in templates
125
    #
126
    # From within a template there are three variables at your disposal:
127
    # * notification
128
    # * controller
129
    # * parameters [converted into a HashWithIndifferentAccess]
130
    #
131
    # Template for key: _notification.article.create_ (erb):
132
    #   <p>
133
    #     Article <strong><%= parameters[:title] %></strong>
134
    #     was posted by <em><%= parameters["author"] %></em>
135
    #     <%= distance_of_time_in_words_to_now(notification.created_at) %>
136
    #   </p>
137
    #
138
    # @param [ActionView::Base] context
139
    # @param [Hash] params Parameters for rendering notifications
140
    # @option params [String, Symbol] :target       (nil)                     Target type name to find template or i18n text
141
    # @option params [String]         :partial_root ("activity_notification/notifications/#{target}", controller.target_view_path, 'activity_notification/notifications/default') Partial template name
142
    # @option params [String]         :partial      (self.key.tr('.', '/'))   Root path of partial template
143
    # @option params [String]         :layout       (nil)                     Layout template name
144
    # @option params [String]         :layout_root  ('layouts')               Root path of layout template
145
    # @option params [String, Symbol] :fallback     (nil)                     Fallback template to use when MissingTemplate is raised. Set :text to use i18n text as fallback.
146
    # @option params [Hash]           :assigns                                Parameters to be set as assigns
147
    # @option params [Hash]           :locals                                 Parameters to be set as locals
148
    # @option params [Hash]           others                                  Parameters to be set as locals
149
    # @return [String] Rendered view or text as string
150
    def render(context, params = {})
24✔
151
      params[:i18n] and return context.render plain: self.text(params)
8,688✔
152

153
      partial = partial_path(*params.values_at(:partial, :partial_root, :target))
8,664✔
154
      layout  = layout_path(*params.values_at(:layout, :layout_root))
8,664✔
155
      assigns = prepare_assigns(params)
8,664✔
156
      locals  = prepare_locals(params)
8,664✔
157

158
      begin
159
        context.render params.merge(partial: partial, layout: layout, assigns: assigns, locals: locals)
8,664✔
160
      rescue ActionView::MissingTemplate => e
6,052✔
161
        if params[:fallback] == :text
8,544✔
162
          context.render plain: self.text(params)
48✔
163
        elsif params[:fallback].present?
8,496✔
164
          partial = partial_path(*params.values_at(:fallback, :partial_root, :target))
8,424✔
165
          context.render params.merge(partial: partial, layout: layout, assigns: assigns, locals: locals)
8,424✔
166
        else
167
          raise e
72✔
168
        end
169
      end
170
    end
171

172
    # Returns partial path from options
173
    #
174
    # @param [String] path Partial template name
175
    # @param [String] root Root path of partial template
176
    # @param [String, Symbol] target Target type name to find template
177
    # @return [String] Partial template path
178
    def partial_path(path = nil, root = nil, target = nil)
24✔
179
      controller = ActivityNotification.get_controller         if ActivityNotification.respond_to?(:get_controller)
17,088✔
180
      root ||= "activity_notification/notifications/#{target}" if target.present?
17,088✔
181
      root ||= controller.target_view_path                     if controller.present? && controller.respond_to?(:target_view_path)
17,088✔
182
      root ||= 'activity_notification/notifications/default'
17,088✔
183
      template_key = notifiable.respond_to?(:overriding_notification_template_key) &&
17,088✔
184
                     notifiable.overriding_notification_template_key(@target, key).present? ?
185
                       notifiable.overriding_notification_template_key(@target, key) :
186
                       key
187
      path ||= template_key.tr('.', '/')
17,088✔
188
      select_path(path, root)
17,088✔
189
    end
190

191
    # Returns layout path from options
192
    #
193
    # @param [String] path Layout template name
194
    # @param [String] root Root path of layout template
195
    # @return [String] Layout template path
196
    def layout_path(path = nil, root = nil)
24✔
197
      path.nil? and return
8,664✔
198
      root ||= 'layouts'
24✔
199
      select_path(path, root)
24✔
200
    end
201

202
    # Returns assigns parameter for view
203
    #
204
    # @param [Hash] params Parameters to add parameters at assigns
205
    # @return [Hash] assigns parameter
206
    def prepare_assigns(params)
24✔
207
      params.delete(:assigns) || {}
8,664✔
208
    end
209

210
    # Returns locals parameter for view
211
    # There are three variables to be add by method:
212
    # * notification
213
    # * controller
214
    # * parameters [converted into a HashWithIndifferentAccess]
215
    #
216
    # @param [Hash] params Parameters to add parameters at locals
217
    # @return [Hash] locals parameter
218
    def prepare_locals(params)
24✔
219
      locals = params.delete(:locals) || {}
8,688✔
220
      prepared_parameters = prepare_parameters(params)
8,688✔
221
      locals.merge\
8,688✔
222
        notification: self,
223
        controller:   ActivityNotification.get_controller,
224
        parameters:   prepared_parameters
225
    end
226

227
    # Prepares parameters with @prepared_params.
228
    # Converted into a HashWithIndifferentAccess.
229
    #
230
    # @param [Hash] params Parameters to prepare
231
    # @return [Hash] Prepared parameters
232
    def prepare_parameters(params)
24✔
233
      @prepared_params ||= ActivityNotification.cast_to_indifferent_hash(parameters).merge(params)
8,688✔
234
    end
235

236

237
    private
24✔
238

239
      # Select template path
240
      # @api private
241
      def select_path(path, root)
24✔
242
        [root, path].map(&:to_s).join('/')
17,112✔
243
      end
244

245
  end
246
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc