Commit f31a118

mo <mo@mokhan.ca>
2018-12-15 18:14:59
display model errors in flash alerts
1 parent d152323
Changed files (4)
app/controllers/registrations_controller.rb
@@ -11,8 +11,7 @@ class RegistrationsController < ApplicationController
     User.create!(user_params)
     redirect_to new_session_path
   rescue ActiveRecord::RecordInvalid => invalid
-    redirect_to new_registration_path,
-                error: invalid.record.errors.full_messages
+    redirect_to new_registration_path, error: invalid.record.errors
   end
 
   private
app/helpers/application_helper.rb
@@ -13,4 +13,14 @@ module ApplicationHelper
       'is-info'
     end
   end
+
+  def flash_error_messages_for(item)
+    if item.is_a?(ActiveModel::Errors)
+      item.keys.map do |key|
+        item.full_messages_for(key).join(' ')
+      end
+    else
+      Array(item)
+    end
+  end
 end
app/views/application/_flash.html.erb
@@ -1,7 +1,8 @@
-<div class="container">
-  <% flash.each do |type, message| %>
-    <% Array(message).each do |value| %>
-      <div data-controller="notification" class="notification <%= alert_class_for(type) %>">
+<div id="container">
+  <% flash.each do |type, item| %>
+    <% alter_class = alert_class_for(type) %>
+    <% flash_error_messages_for(item).each do |value| %>
+      <div data-controller="notification" class="notification <%= alter_class %>">
         <button data-action="click->notification#close" class="delete"></button>
         <%= value %>
       </div>
spec/helpers/application_helper_spec.rb
@@ -0,0 +1,58 @@
+require 'rails_helper'
+
+RSpec.describe ApplicationHelper do
+  describe "#alert_class_for" do
+    specify { expect(helper.alert_class_for(:notice)).to eql('is-success') }
+    specify { expect(helper.alert_class_for('notice')).to eql('is-success') }
+    specify { expect(helper.alert_class_for(:warning)).to eql('is-warning') }
+    specify { expect(helper.alert_class_for(:error)).to eql('is-danger') }
+    specify { expect(helper.alert_class_for(:info)).to eql('is-info') }
+  end
+
+  describe "#flash_error_messages_for" do
+    context "when the item is an array of strings" do
+      it 'returns the array of strings' do
+        expect(helper.flash_error_messages_for(['error'])).to match_array(['error'])
+      end
+
+      context "when the item is a single string" do
+        it 'returns an array of strings when' do
+          expect(helper.flash_error_messages_for('error')).to match_array(['error'])
+        end
+      end
+
+      context "when the item is an instance of ActiveModel::Errors" do
+        class User
+          extend ActiveModel::Naming
+
+          attr_reader :email, :password
+
+          def read_attribute_for_validation(attr)
+            send(attr)
+          end
+
+          def self.human_attribute_name(attr, options = {})
+            attr.to_s.titleize
+          end
+
+          def self.lookup_ancestors
+            [self]
+          end
+        end
+        let(:user) { User.new }
+
+        it "returns an array item for each attribute" do
+          errors = ActiveModel::Errors.new(user)
+          errors.add(:email, 'has already been taken.')
+          errors.add(:password, 'must contain at least one upper case character.')
+          errors.add(:password, 'must contain at least one numeric character.')
+
+          expect(helper.flash_error_messages_for(errors)).to match_array([
+            'Email has already been taken.',
+            'Password must contain at least one upper case character. Password must contain at least one numeric character.',
+          ])
+        end
+      end
+    end
+  end
+end