social_stream-base 0.13.2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/activities.js.erb +5 -5
- data/app/assets/javascripts/social_stream-base.js +2 -0
- data/app/assets/stylesheets/cheesecake.css.scss +13 -0
- data/app/controllers/omniauth_callbacks_controller.rb +3 -3
- data/app/helpers/notifications_helper.rb +2 -2
- data/app/models/user.rb +15 -14
- data/app/views/cheesecake/_cheesecake.html.erb +69 -1
- data/app/views/frontpage/_social_networks.html.erb +1 -1
- data/app/views/layouts/application.html.erb +6 -1
- data/lib/acts_as_taggable_on/social_stream.rb +59 -31
- data/lib/i18n-js/social_stream-base.rb +36 -0
- data/lib/social_stream/base/dependencies.rb +6 -2
- data/lib/social_stream/base/version.rb +1 -1
- data/lib/social_stream/controllers/cancan_devise_integration.rb +15 -18
- data/lib/social_stream/controllers/helpers.rb +81 -83
- data/lib/social_stream/controllers/i18n_integration.rb +11 -13
- data/lib/social_stream/controllers/objects.rb +4 -7
- data/lib/social_stream/controllers/subjects.rb +3 -5
- data/lib/social_stream/models/channeled.rb +24 -26
- data/lib/social_stream/models/object.rb +57 -61
- data/lib/social_stream/models/subject.rb +4 -8
- data/lib/social_stream/models/subtype.rb +36 -34
- data/lib/social_stream/models/supertype.rb +17 -21
- data/lib/tasks/db/populate.rake +11 -3
- data/social_stream-base.gemspec +9 -5
- data/spec/dummy/config/initializers/devise.rb +1 -1
- metadata +99 -65
@@ -57,7 +57,7 @@ activate_anti_rebounds = function(){
|
|
57
57
|
$(this).find('input[type=text]').each(function() {
|
58
58
|
$(this).blur().attr('readonly', true);
|
59
59
|
});
|
60
|
-
$("#masterSubmitButton").val(
|
60
|
+
$("#masterSubmitButton").val(I18n.t('activity.sending') + '...').attr("disabled", true);
|
61
61
|
|
62
62
|
// Add _relation_ids[] parameter from authorization selector
|
63
63
|
$('.liveAdded').remove();
|
@@ -81,7 +81,7 @@ activate_anti_rebounds = function(){
|
|
81
81
|
$(this).blur().attr('readonly', true);
|
82
82
|
});
|
83
83
|
$(this).find(".submitActivity").each(function() {
|
84
|
-
$(this).val(
|
84
|
+
$(this).val(I18n.t('activity.sending') + '...').attr("disabled", true);
|
85
85
|
});
|
86
86
|
return true;
|
87
87
|
});
|
@@ -90,9 +90,9 @@ activate_anti_rebounds = function(){
|
|
90
90
|
|
91
91
|
unblock_all_forms = function() {
|
92
92
|
//Sharing buttons
|
93
|
-
$(".submitActivity").val(
|
93
|
+
$(".submitActivity").val(I18n.t('share')).removeAttr("disabled");
|
94
94
|
//Header activities form
|
95
|
-
$("#masterSubmitButton").val(
|
95
|
+
$("#masterSubmitButton").val(I18n.t('share')).removeAttr("disabled");
|
96
96
|
$('#wrapper_activities_header form').find('input[type=text]').each(function() {
|
97
97
|
$(this).removeAttr("readonly").val("").blur();
|
98
98
|
});
|
@@ -141,7 +141,7 @@ $(function() {
|
|
141
141
|
//check if there are more than 3 comments
|
142
142
|
if (comments.size() > 3){
|
143
143
|
$(this).prepend("<div class='hide_show_comments'><a href='#' onclick='showAllComments(\""+
|
144
|
-
$(this).attr('id') +"\"); return false;'
|
144
|
+
$(this).attr('id') +"\"); return false;'>" + I18n.t('comment.view_all') + "(" +
|
145
145
|
comments.size() + ")</a></div><div class='space_comments'></div>");
|
146
146
|
comments.slice(0,comments.size()-2).hide();
|
147
147
|
//hide alto space_comments
|
@@ -84,10 +84,23 @@
|
|
84
84
|
padding: 5px;
|
85
85
|
display: none;
|
86
86
|
max-height: 200px;
|
87
|
+
overflow-y: auto;
|
87
88
|
}
|
88
89
|
#contacts_changes_details ul{
|
89
90
|
padding-left: 20px;
|
90
91
|
}
|
92
|
+
#contacts_changes_details .change_deleted{
|
93
|
+
font-weight: bold;
|
94
|
+
color: $error-color;
|
95
|
+
}
|
96
|
+
#contacts_changes_details .change_modified{
|
97
|
+
font-weight: bold;
|
98
|
+
color: $alert-color;
|
99
|
+
}
|
100
|
+
#contacts_changes_details .change_added{
|
101
|
+
font-weight: bold;
|
102
|
+
color: $success-color;
|
103
|
+
}
|
91
104
|
#contacts_grid .actor {
|
92
105
|
width: 48px;
|
93
106
|
height: 48px;
|
@@ -1,15 +1,15 @@
|
|
1
1
|
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
2
2
|
def facebook
|
3
|
-
#print env['omniauth.auth']
|
4
3
|
@user = User.find_or_create_for_facebook_oauth(env['omniauth.auth'],current_user)
|
4
|
+
|
5
5
|
if @user.persisted?
|
6
6
|
sign_in_and_redirect @user, :event => :authentication
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
#print env['omniauth.auth']
|
10
|
+
def linkedin
|
12
11
|
@user = User.find_or_create_for_linkedin_oauth(env['omniauth.auth'],current_user)
|
12
|
+
|
13
13
|
if @user.persisted?
|
14
14
|
sign_in_and_redirect @user, :event => :authentication
|
15
15
|
end
|
@@ -10,7 +10,7 @@ module NotificationsHelper
|
|
10
10
|
act_obj.title.truncate(30, :separator => ' ')
|
11
11
|
elsif act_obj.respond_to? :url and (not act_obj.url.nil?)
|
12
12
|
act_obj.url.truncate(30, :separator => ' ')
|
13
|
-
else t('notification.default')
|
13
|
+
else I18n.t('notification.default')
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -21,7 +21,7 @@ module NotificationsHelper
|
|
21
21
|
elsif act_obj.respond_to? :description and (not act_obj.description.nil?)
|
22
22
|
sanitize(act_obj.description.truncate(100, :separator =>' '))
|
23
23
|
else
|
24
|
-
t('notification.watch_it')
|
24
|
+
I18n.t('notification.watch_it')
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/app/models/user.rb
CHANGED
@@ -115,26 +115,27 @@ class User < ActiveRecord::Base
|
|
115
115
|
record
|
116
116
|
end
|
117
117
|
|
118
|
-
def find_or_create_for_facebook_oauth(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
user = User.create!(:name => data["name"], :email => data["email"], :password => Devise.friendly_token[0,20])
|
118
|
+
def find_or_create_for_facebook_oauth(hash, signed_in_resource = nil)
|
119
|
+
puts hash.inspect
|
120
|
+
auth = Authentication.find_by_provider_and_uid(hash["provider"], hash["uid"])
|
121
|
+
user = User.find_by_email(hash["info"]["email"])
|
122
|
+
|
123
|
+
if user.nil?
|
124
|
+
user = User.create!(:name => hash["info"]["name"], :email => hash["info"]["email"], :password => Devise.friendly_token[0,20])
|
126
125
|
end
|
127
|
-
|
128
|
-
|
126
|
+
|
127
|
+
if auth.nil?
|
128
|
+
auth = Authentication.create!(:user_id => user.id, :uid =>hash["uid"], :provider => hash["provider"])
|
129
129
|
end
|
130
|
+
|
130
131
|
user
|
131
132
|
end
|
132
133
|
|
133
|
-
def find_or_create_for_linkedin_oauth(
|
134
|
-
auth = Authentication.find_by_uid_and_provider(
|
134
|
+
def find_or_create_for_linkedin_oauth(hash,signed_in_resource=nil)
|
135
|
+
auth = Authentication.find_by_uid_and_provider(hash["uid"],hash["provider"])
|
135
136
|
if auth==nil
|
136
|
-
user = User.create!(:name =>
|
137
|
-
auth = Authentication.create!(:user_id => user.id, :uid =>
|
137
|
+
user = User.create!(:name => hash["info"]["name"], :email => 'demo@socialstream.com', :password => Devise.friendly_token[0,20])
|
138
|
+
auth = Authentication.create!(:user_id => user.id, :uid =>hash["uid"], :provider => hash["provider"])
|
138
139
|
user
|
139
140
|
else
|
140
141
|
user = User.find_by_id(auth.user_id)
|
@@ -48,7 +48,75 @@ $(function(){
|
|
48
48
|
cheesecakeData.highlightedSectorCallback(cheese);
|
49
49
|
});
|
50
50
|
cheese.onChange = function(cheesecake){
|
51
|
-
|
51
|
+
var initial = cheesecake.getInitialState();
|
52
|
+
var changes = cheesecake.getChanges();
|
53
|
+
var changes_html = "";
|
54
|
+
var actors = changes.actors;
|
55
|
+
$("#contacts_save_changes").val(JSON.stringify(changes));
|
56
|
+
for(var i in actors){
|
57
|
+
actor = actors[i];
|
58
|
+
if(actor.justAdded){
|
59
|
+
var new_subsectors = actor.subsectors;
|
60
|
+
var new_subsectors_string = "";
|
61
|
+
for(var i in new_subsectors){
|
62
|
+
if(i > 0) new_subsectors_string += ", ";
|
63
|
+
new_subsectors_string += cheesecake.getSubsectorById(new_subsectors[i]).label;
|
64
|
+
}
|
65
|
+
changes_html += "<div class=\"change_added\">" + actor.name + " has been removed from " + old_subsectors_string + "</div>";
|
66
|
+
}else if(actor.subsectors.length==0){
|
67
|
+
var old_subsectors = [];
|
68
|
+
var old_subsectors_string = "";
|
69
|
+
for(var i in initial.actors){
|
70
|
+
if(actor.id==initial.actors[i].id){
|
71
|
+
old_subsectors = initial.actors[i].subsectors;
|
72
|
+
break;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
for(var i in old_subsectors){
|
76
|
+
if(i > 0) old_subsectors_string += ", ";
|
77
|
+
old_subsectors_string += cheesecake.getSubsectorById(old_subsectors[i]).label;
|
78
|
+
}
|
79
|
+
changes_html += "<div class=\"change_deleted\">" + actor.name + " has been removed from " + old_subsectors_string + "</div>";
|
80
|
+
}else{
|
81
|
+
var old_subsectors = [];
|
82
|
+
var new_subsectors = actor.subsectors;
|
83
|
+
var left_subsectors = "";
|
84
|
+
var joined_subsectors = "";
|
85
|
+
for(var i in initial.actors){
|
86
|
+
if(actor.id==initial.actors[i].id){
|
87
|
+
old_subsectors = initial.actors[i].subsectors;
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
for(var i in old_subsectors){
|
92
|
+
if(new_subsectors.indexOf(old_subsectors[i])==-1){
|
93
|
+
if(left_subsectors.length!=0){
|
94
|
+
left_subsectors += ", ";
|
95
|
+
}
|
96
|
+
left_subsectors += cheesecake.getSubsectorById(old_subsectors[i]).label;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
for(var i in new_subsectors){
|
100
|
+
if(old_subsectors.indexOf(new_subsectors[i])==-1){
|
101
|
+
if(joined_subsectors.length!=0){
|
102
|
+
joined_subsectors += ", ";
|
103
|
+
}
|
104
|
+
joined_subsectors += cheesecake.getSubsectorById(new_subsectors[i]).label;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
if((joined_subsectors.length!=0)&&(left_subsectors.length!=0)){
|
108
|
+
changes_html += "<div class=\"change_modified\">" + actor.name + " has been removed from " + left_subsectors + " and added to " + joined_subsectors + "</div>";
|
109
|
+
}else if(joined_subsectors.length!=0){
|
110
|
+
changes_html += "<div class=\"change_added\">" + actor.name + " has been added to " + joined_subsectors + "</div>";
|
111
|
+
}else{
|
112
|
+
changes_html += "<div class=\"change_deleted\">" + actor.name + " has been removed from " + left_subsectors + "</div>";
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
$("#contacts_changes_details").html(changes_html);
|
117
|
+
if (!$("#contacts_changes_details").is (":visible")){
|
118
|
+
$("#contacts_changes_details").slideToggle("slow");
|
119
|
+
}
|
52
120
|
}
|
53
121
|
if(cheese.grid.actors.length > 30){
|
54
122
|
var extra_text = ["<%= t('cheesecake.hidden_contact.one')%>","<%= t('cheesecake.hidden_contact.other')%>"];
|
@@ -1,3 +1,3 @@
|
|
1
1
|
<span>|</span>
|
2
2
|
<%= link_to image_tag('btn/facebook.png'), user_omniauth_authorize_path(:facebook), :class => "menu_icon" %>
|
3
|
-
<%= link_to image_tag('btn/linkedin.png'), user_omniauth_authorize_path(:
|
3
|
+
<%= link_to image_tag('btn/linkedin.png'), user_omniauth_authorize_path(:linkedin), :class => "menu_icon" %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<!-- HTML5 DOCTYPE -->
|
2
2
|
<!DOCTYPE html>
|
3
|
-
<html lang="
|
3
|
+
<html lang="<%= I18n.locale.to_s %>">
|
4
4
|
<head>
|
5
5
|
<meta charset="utf-8">
|
6
6
|
<title><%= yield(:title).empty? ? t('site.name') : yield(:title)%></title>
|
@@ -20,6 +20,11 @@
|
|
20
20
|
<%= csrf_meta_tag %>
|
21
21
|
<% end %>
|
22
22
|
|
23
|
+
<script type="text/javascript">
|
24
|
+
I18n.defaultLocale = "<%= I18n.default_locale %>";
|
25
|
+
I18n.locale = "<%= I18n.locale %>";
|
26
|
+
</script>
|
27
|
+
|
23
28
|
<script type="text/javascript">
|
24
29
|
$(document).ready(function() {
|
25
30
|
<%= yield :javascript %>
|
@@ -1,14 +1,69 @@
|
|
1
1
|
require "acts_as_taggable_on/acts_as_taggable_on/dirty"
|
2
2
|
|
3
|
+
module ActsAsTaggableOn::Taggable::Core::ClassMethods
|
4
|
+
def initialize_acts_as_taggable_on_core
|
5
|
+
tag_types.map(&:to_s).each do |tags_type|
|
6
|
+
tag_type = tags_type.to_s.singularize
|
7
|
+
context_taggings = "#{tag_type}_taggings".to_sym
|
8
|
+
context_tags = tags_type.to_sym
|
9
|
+
|
10
|
+
class_eval do
|
11
|
+
has_many context_taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
|
12
|
+
:conditions => ["#{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_type]
|
13
|
+
has_many context_tags, :through => context_taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
|
14
|
+
end
|
15
|
+
|
16
|
+
class_eval %(
|
17
|
+
def #{tag_type}_list
|
18
|
+
tag_list_on('#{tags_type}')
|
19
|
+
end
|
20
|
+
|
21
|
+
def #{tag_type}_list=(new_tags)
|
22
|
+
set_tag_list_on('#{tags_type}', new_tags)
|
23
|
+
end
|
24
|
+
|
25
|
+
def all_#{tags_type}_list
|
26
|
+
all_tags_list_on('#{tags_type}')
|
27
|
+
end
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ActsAsTaggableOn::Taggable::Core::InstanceMethods
|
34
|
+
def set_tag_list_on(context, new_list)
|
35
|
+
add_custom_context(context)
|
36
|
+
|
37
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
38
|
+
process_dirty_object(context, new_list) unless custom_contexts.include?(context.to_s)
|
39
|
+
|
40
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.from(new_list))
|
41
|
+
end
|
42
|
+
|
43
|
+
def process_dirty_object(context,new_list)
|
44
|
+
value = new_list.is_a?(Array) ? new_list.join(', ') : new_list
|
45
|
+
attrib = "#{context.to_s.singularize}_list"
|
46
|
+
|
47
|
+
if changed_attributes.include?(attrib)
|
48
|
+
# The attribute already has an unsaved change.
|
49
|
+
old = changed_attributes[attrib]
|
50
|
+
changed_attributes.delete(attrib) if (old.to_s == value.to_s)
|
51
|
+
else
|
52
|
+
old = tag_list_on(context).to_s
|
53
|
+
changed_attributes[attrib] = old if (old.to_s != value.to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
3
58
|
module ActsAsTaggableOn::Taggable
|
4
59
|
def acts_as_taggable_on(*tag_types)
|
5
60
|
tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
|
6
61
|
|
7
62
|
if taggable?
|
8
|
-
|
63
|
+
self.tag_types = (self.tag_types + tag_types).uniq
|
9
64
|
else
|
10
|
-
|
11
|
-
|
65
|
+
class_attribute :tag_types
|
66
|
+
self.tag_types = tag_types
|
12
67
|
|
13
68
|
class_eval do
|
14
69
|
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging"
|
@@ -18,6 +73,7 @@ module ActsAsTaggableOn::Taggable
|
|
18
73
|
true
|
19
74
|
end
|
20
75
|
|
76
|
+
include ActsAsTaggableOn::Utils
|
21
77
|
include ActsAsTaggableOn::Taggable::Core
|
22
78
|
include ActsAsTaggableOn::Taggable::Collection
|
23
79
|
include ActsAsTaggableOn::Taggable::Cache
|
@@ -28,31 +84,3 @@ module ActsAsTaggableOn::Taggable
|
|
28
84
|
end
|
29
85
|
end
|
30
86
|
end
|
31
|
-
|
32
|
-
|
33
|
-
module ActsAsTaggableOn::Taggable::Core::InstanceMethods
|
34
|
-
def set_tag_list_on(context, new_list)
|
35
|
-
add_custom_context(context)
|
36
|
-
|
37
|
-
variable_name = "@#{context.to_s.singularize}_list"
|
38
|
-
process_dirty_object(context, new_list)
|
39
|
-
|
40
|
-
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.from(new_list))
|
41
|
-
end
|
42
|
-
|
43
|
-
def process_dirty_object(context,new_list)
|
44
|
-
value = new_list.is_a?(Array) ? new_list.join(', ') : new_list
|
45
|
-
attr = "#{context.to_s.singularize}_list"
|
46
|
-
|
47
|
-
if changed_attributes.include?(attr)
|
48
|
-
# The attribute already has an unsaved change.
|
49
|
-
old = changed_attributes[attr]
|
50
|
-
changed_attributes.delete(attr) if (old.to_s == value.to_s)
|
51
|
-
else
|
52
|
-
old = tag_list_on(context).to_s
|
53
|
-
changed_attributes[attr] = old if (old.to_s != value.to_s)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Monkey patch https://github.com/fnando/i18n-js/commit/888e9c59dfb5164a85f136705186b02d9ef33d5a
|
2
|
+
#
|
3
|
+
# Remove with i18n-js > 2.1.2
|
4
|
+
require 'i18n-js'
|
5
|
+
|
6
|
+
module SimplesIdeias
|
7
|
+
module I18n
|
8
|
+
class Engine
|
9
|
+
initializers.pop
|
10
|
+
|
11
|
+
initializer "i18n-js.asset_dependencies", :after => "sprockets.environment" do
|
12
|
+
next unless I18n.has_asset_pipeline?
|
13
|
+
|
14
|
+
config = I18n.config_file
|
15
|
+
cache_file = I18n::Engine.load_path_hash_cache
|
16
|
+
|
17
|
+
Rails.application.assets.register_preprocessor "application/javascript", :"i18n-js_dependencies" do |context, data|
|
18
|
+
if context.logical_path == I18N_TRANSLATIONS_ASSET
|
19
|
+
context.depend_on(config) if I18n.config?
|
20
|
+
# also set up dependencies on every locale file
|
21
|
+
::I18n.load_path.each {|path| context.depend_on(path)}
|
22
|
+
|
23
|
+
# Set up a dependency on the contents of the load path
|
24
|
+
# itself. In some situations it is possible to get here
|
25
|
+
# before the path hash cache file has been written; in
|
26
|
+
# this situation, write it now.
|
27
|
+
I18n::Engine.write_hash! unless File.exists?(cache_file)
|
28
|
+
context.depend_on(cache_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
data
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -23,7 +23,9 @@ require 'avatars_for_rails'
|
|
23
23
|
# Pagination
|
24
24
|
require 'kaminari'
|
25
25
|
# Oauth
|
26
|
-
require 'omniauth
|
26
|
+
require 'omniauth'
|
27
|
+
require 'omniauth-facebook'
|
28
|
+
require 'omniauth-linkedin'
|
27
29
|
#Tags
|
28
30
|
require 'acts-as-taggable-on'
|
29
31
|
require 'acts_as_taggable_on/social_stream'
|
@@ -43,5 +45,7 @@ require 'sass-rails'
|
|
43
45
|
require 'rails_autolink'
|
44
46
|
# SocialCheesecake
|
45
47
|
require 'social_cheesecake'
|
46
|
-
|
48
|
+
# I18n-js
|
49
|
+
require 'i18n-js'
|
50
|
+
require 'i18n-js/social_stream-base'
|
47
51
|
|
@@ -4,27 +4,24 @@ module SocialStream
|
|
4
4
|
module CancanDeviseIntegration
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
|
7
|
+
private
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if params[:s].present? && controller_name != 'home'
|
21
|
-
redirect_to :home
|
22
|
-
else
|
23
|
-
raise exception
|
24
|
-
end
|
9
|
+
# Catch some authorization errors:
|
10
|
+
#
|
11
|
+
# * Redirect to home when the user changes the session and the resource
|
12
|
+
# is not accesible with the new representation
|
13
|
+
#
|
14
|
+
# * Redirect to login if the user is trying to access a protected resource
|
15
|
+
# and she is not authenticated
|
16
|
+
def rescue_from_access_denied(exception)
|
17
|
+
if user_signed_in?
|
18
|
+
if params[:s].present? && controller_name != 'home'
|
19
|
+
redirect_to :home
|
25
20
|
else
|
26
|
-
|
21
|
+
raise exception
|
27
22
|
end
|
23
|
+
else
|
24
|
+
redirect_to new_user_session_path
|
28
25
|
end
|
29
26
|
end
|
30
27
|
end
|