Support Users Directly Uploading Profile Pictures.
* Adds a `picture` attribute to `User`. * Preserves Gravatar as a fallback option. * Now, you should use `user.profile_picturer` instead of `gravatar_url` * TODO: Ensure `profile_picture` handles sizing right for uploaded images.
This commit is contained in:
parent
b66f69599a
commit
3883188dcd
13 changed files with 43 additions and 18 deletions
|
|
@ -24,8 +24,8 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Only allow a trusted parameter "white list" through.
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:name, :biography, :nickname, :affiliation)
|
params.require(:user).permit(:name, :biography, :nickname, :affiliation,
|
||||||
|
:picture, :picture_cache)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,13 @@ class User < ApplicationRecord
|
||||||
has_paper_trail on: [:create, :update], ignore: [:sign_in_count, :remember_created_at, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :unconfirmed_email,
|
has_paper_trail on: [:create, :update], ignore: [:sign_in_count, :remember_created_at, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :unconfirmed_email,
|
||||||
:avatar_content_type, :avatar_file_size, :avatar_updated_at, :updated_at, :confirmation_sent_at, :confirmation_token, :reset_password_token]
|
:avatar_content_type, :avatar_file_size, :avatar_updated_at, :updated_at, :confirmation_sent_at, :confirmation_token, :reset_password_token]
|
||||||
|
|
||||||
|
# A user may have an uploaded avatar or use gravatar.
|
||||||
|
# The uploaded picture takes precedence.
|
||||||
include Gravtastic
|
include Gravtastic
|
||||||
gravtastic size: 32
|
gravtastic size: 32
|
||||||
|
|
||||||
|
mount_uploader :picture, PictureUploader, mount_on: :picture
|
||||||
|
|
||||||
before_create :setup_role
|
before_create :setup_role
|
||||||
|
|
||||||
after_save :touch_events
|
after_save :touch_events
|
||||||
|
|
@ -151,6 +155,14 @@ class User < ApplicationRecord
|
||||||
ticket_purchases.find_by(conference_id: conference.id).present?
|
ticket_purchases.find_by(conference_id: conference.id).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a user's profile picture URL.
|
||||||
|
# Partials should *not* directly call `gravatar_url`
|
||||||
|
def profile_picture(opts)
|
||||||
|
# TODO: Figure out how to align sizes?
|
||||||
|
picture.thumb.url || gravatar_url(opts)
|
||||||
|
end
|
||||||
|
|
||||||
def self.for_ichain_username(username, attributes)
|
def self.for_ichain_username(username, attributes)
|
||||||
user = find_by(username: username)
|
user = find_by(username: username)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
- @top_submitter.each do |key, value|
|
- @top_submitter.each do |key, value|
|
||||||
.row.top-submitter
|
.row.top-submitter
|
||||||
.col-md-2
|
.col-md-2
|
||||||
= image_tag(key.gravatar_url(size: '25'), title: "Yo #{key.name}!", alt: '', 'class' => 'img-circle img-responsive text-center')
|
= image_tag(key.profile_picture(size: '25'), title: "Yo #{key.name}!", alt: '', 'class' => 'img-circle img-responsive text-center')
|
||||||
.col-md-10
|
.col-md-10
|
||||||
%h4
|
%h4
|
||||||
= link_to key.name, admin_user_path(key)
|
= link_to key.name, admin_user_path(key)
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@
|
||||||
Registered
|
Registered
|
||||||
= word_pluralize(@conference.participants.count, 'Attendee')
|
= word_pluralize(@conference.participants.count, 'Attendee')
|
||||||
- @conference.participants.each do |participant|
|
- @conference.participants.each do |participant|
|
||||||
= link_to image_tag(participant.gravatar_url(size: '25'), title: "#{participant.name}!", class: 'img-circle'), user_path(participant)
|
= link_to image_tag(participant.profile_picture(size: '25'), title: "#{participant.name}!", class: 'img-circle'), user_path(participant)
|
||||||
.col-md-4.col-md-offset-2
|
.col-md-4.col-md-offset-2
|
||||||
- if @conference.program.speakers.confirmed.any?
|
- if @conference.program.speakers.confirmed.any?
|
||||||
%h4
|
%h4
|
||||||
|
|
@ -156,4 +156,4 @@
|
||||||
Confirmed
|
Confirmed
|
||||||
= word_pluralize(@conference.program.speakers.confirmed.count, 'Speaker')
|
= word_pluralize(@conference.program.speakers.confirmed.count, 'Speaker')
|
||||||
- @conference.program.speakers.confirmed.each do |speaker|
|
- @conference.program.speakers.confirmed.each do |speaker|
|
||||||
= link_to image_tag(speaker.gravatar_url(size: '25'), title: "#{speaker.name}!", class: 'img-circle'), user_path(speaker)
|
= link_to image_tag(speaker.profile_picture(size: '25'), title: "#{speaker.name}!", class: 'img-circle'), user_path(speaker)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
= link_to(conference_program_proposal_path(conference_id,
|
= link_to(conference_program_proposal_path(conference_id,
|
||||||
event),
|
event),
|
||||||
class: 'thumbnail') do
|
class: 'thumbnail') do
|
||||||
= image_tag speaker.gravatar_url(size: 300),
|
= image_tag speaker.profile_picture(size: 300),
|
||||||
class: ['img-responsive', 'img-circle'],
|
class: ['img-responsive', 'img-circle'],
|
||||||
title: speaker.name
|
title: speaker.name
|
||||||
.caption
|
.caption
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
%li.dropdown
|
%li.dropdown
|
||||||
%a.dropdown-toggle{"data-toggle" => "dropdown", href: '#', id: "current-user-detail"}
|
%a.dropdown-toggle{"data-toggle" => "dropdown", href: '#', id: "current-user-detail"}
|
||||||
= current_user.name
|
= current_user.name
|
||||||
= image_tag(current_user.gravatar_url(size: '18'), title: "Yo #{current_user.name}!", alt: '')
|
= image_tag(current_user.profile_picture(size: '18'), title: "Yo #{current_user.name}!", alt: '')
|
||||||
%b.caret
|
%b.caret
|
||||||
%ul.dropdown-menu
|
%ul.dropdown-menu
|
||||||
= render 'layouts/user_menu'
|
= render 'layouts/user_menu'
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
%meta{ property: "og:description", content: @event.abstract }
|
%meta{ property: "og:description", content: @event.abstract }
|
||||||
%meta{ property: "og:site_name", content: (ENV['OSEM_NAME'] || 'OSEM') }
|
%meta{ property: "og:site_name", content: (ENV['OSEM_NAME'] || 'OSEM') }
|
||||||
- if @speakers_ordered.any?
|
- if @speakers_ordered.any?
|
||||||
%meta{ property: "og:image", content: @speakers_ordered.first.gravatar_url }
|
%meta{ property: "og:image", content: @speakers_ordered.first.profile_picture }
|
||||||
%meta{ property: "og:image:secure_url", content: @speakers_ordered.first.gravatar_url }
|
%meta{ property: "og:image:secure_url", content: @speakers_ordered.first.profile_picture }
|
||||||
|
|
||||||
.container
|
.container
|
||||||
.row.page-header
|
.row.page-header
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
.speakerinfo
|
.speakerinfo
|
||||||
.row
|
.row
|
||||||
.col-md-4
|
.col-md-4
|
||||||
= image_tag speaker.gravatar_url(:size => 120), class: 'img-responsive img-rounded'
|
= image_tag speaker.profile_picture(:size => 120), class: 'img-responsive img-rounded'
|
||||||
.col-md-8
|
.col-md-8
|
||||||
%h4
|
%h4
|
||||||
= link_to speaker.name, user_path(speaker.id)
|
= link_to speaker.name, user_path(speaker.id)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.panel.panel-default.event-panel{ onClick: 'eventClicked(event, this);', "data-url" => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" }
|
.panel.panel-default.event-panel{ onClick: 'eventClicked(event, this);', "data-url" => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" }
|
||||||
.panel-body
|
.panel-body
|
||||||
- event.speakers_ordered.each do |speaker|
|
- event.speakers_ordered.each do |speaker|
|
||||||
= image_tag speaker.gravatar_url, :class => "img-circle pull-right all-speaker-pic", |
|
= image_tag speaker.profile_picture, :class => "img-circle pull-right all-speaker-pic", |
|
||||||
:alt => speaker.name, |
|
:alt => speaker.name, |
|
||||||
:title => speaker.name |
|
:title => speaker.name |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@
|
||||||
= event.title
|
= event.title
|
||||||
|
|
||||||
- event.speakers_ordered.each do |speaker|
|
- event.speakers_ordered.each do |speaker|
|
||||||
= image_tag speaker.gravatar_url, :class => "img-circle pull-right speaker-pic", |
|
= image_tag speaker.profile_picture, :class => "img-circle pull-right speaker-pic", |
|
||||||
:alt => speaker.name, |
|
:alt => speaker.name, |
|
||||||
:title => speaker.name, |
|
:title => speaker.name, |
|
||||||
:style => "height: #{ speaker_height(@rooms) }px; width: #{ speaker_width(@rooms) }px;"
|
:style => "height: #{ speaker_height(@rooms) }px; width: #{ speaker_width(@rooms) }px;"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,16 @@
|
||||||
= f.input :nickname, as: :string, hint: 'This is how the other users see you, not your real name'
|
= f.input :nickname, as: :string, hint: 'This is how the other users see you, not your real name'
|
||||||
.control-label
|
.control-label
|
||||||
= "Avatar"
|
= "Avatar"
|
||||||
= image_tag(@user.gravatar_url(size: '48'), title: "Yo #{@user.name}!", alt: '')
|
= image_tag(@user.profile_picture(size: '48'), title: "Yo #{@user.name}!", alt: '')
|
||||||
= link_to 'Change your avatar here', 'https://gravatar.com'
|
= link_to 'Change your avatar here', 'https://gravatar.com'
|
||||||
|
%br
|
||||||
|
%p
|
||||||
|
Or upload a picture.
|
||||||
|
= image_tag f.object.picture.thumb.url if f.object.picture?
|
||||||
|
- if @user.picture?
|
||||||
|
= image_tag(@user.picture.thumb.url, width: '20%')
|
||||||
|
= f.input :picture, hint: 'If you upload a picture, it will be used in place of Gravatar.'
|
||||||
|
|
||||||
= f.input :affiliation, as: :string,
|
= f.input :affiliation, as: :string,
|
||||||
hint: 'This could be a company, a user group, or nothing at all.'
|
hint: 'This could be a company, a user group, or nothing at all.'
|
||||||
= f.input :biography, input_html: { rows: 5, data: { provide: 'markdown' } },
|
= f.input :biography, input_html: { rows: 5, data: { provide: 'markdown' } },
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
.col-md-12
|
.col-md-12
|
||||||
.page-header
|
.page-header
|
||||||
%h1
|
%h1
|
||||||
= image_tag(@user.gravatar_url(size: '48'), title: "Yo #{@user.name}!", alt: '')
|
= image_tag(@user.profile_picture(size: '48'), title: "Yo #{@user.name}!", alt: '')
|
||||||
= @user.name
|
= @user.name
|
||||||
%small
|
%small
|
||||||
= @user.nickname
|
= @user.nickname
|
||||||
|
|
|
||||||
5
db/migrate/20200715034647_add_picture_to_users.rb
Normal file
5
db/migrate/20200715034647_add_picture_to_users.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddPictureToUsers < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :users, :picture, :string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_07_15_001812) do
|
ActiveRecord::Schema.define(version: 2020_07_15_034647) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
@ -591,6 +591,7 @@ ActiveRecord::Schema.define(version: 2020_07_15_001812) do
|
||||||
t.boolean "is_admin", default: false
|
t.boolean "is_admin", default: false
|
||||||
t.string "username"
|
t.string "username"
|
||||||
t.boolean "is_disabled", default: false
|
t.boolean "is_disabled", default: false
|
||||||
|
t.string "picture"
|
||||||
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
||||||
t.index ["email"], name: "index_users_on_email", unique: true
|
t.index ["email"], name: "index_users_on_email", unique: true
|
||||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue