Implement Badge & BadgeAchievement model (#273)

* Create migration for Badge & BadgeAchievement

* Create Badge model with spec & BadgeUploader

* Create BadgeAchievement with spec

* Add badges & badge_achievements assoc to User

* Fix typo

* Clean up BadgeUploader

* Remove storage config & Fix lint

* Add allow-duplicate-badge spec
This commit is contained in:
Mac Siri 2018-05-07 13:35:16 -04:00 committed by Ben Halpern
parent 524052234a
commit 1663e7e2c8
12 changed files with 141 additions and 15 deletions

17
app/models/badge.rb Normal file
View file

@ -0,0 +1,17 @@
class Badge < ApplicationRecord
mount_uploader :badge_image, BadgeUploader
has_many :badge_achievements
has_many :users, through: :badge_achievements
validates :title, presence: true, uniqueness: true
validates :description, presence: true
before_validation :generate_slug
private
def generate_slug
self.slug = title.to_s.downcase.tr(" ", "-").gsub(/[^\w-]/, "").tr("_", "")
end
end

View file

@ -0,0 +1,5 @@
class BadgeAchievement < ApplicationRecord
belongs_to :user
belongs_to :badge
belongs_to :rewarder, class_name: "User"
end

View file

@ -13,6 +13,8 @@ class User < ApplicationRecord
belongs_to :organization, optional: true
has_many :articles
has_many :badge_achievements
has_many :badges, through: :badge_achievements
has_many :collections
has_many :comments
has_many :email_messages, class_name: "Ahoy::Message"

View file

@ -0,0 +1,11 @@
class BadgeUploader < CarrierWave::Uploader::Base
include CarrierWave::BombShelter
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_whitelist
%w(jpg jpeg gif png)
end
end

View file

@ -1,20 +1,19 @@
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'
require "carrierwave/storage/abstract"
require "carrierwave/storage/file"
require "carrierwave/storage/fog"
CarrierWave.configure do |config|
if Rails.env.development? || Rails.env.test?
config.storage = :file
else
# config.fog_provider = 'fog-aws'
config.storage = :fog
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => ENV['AWS_ID'],
:aws_secret_access_key => ENV['AWS_SECRET'],
:region => 'us-east-1'
provider: "AWS",
aws_access_key_id: ENV["AWS_ID"],
aws_secret_access_key: ENV["AWS_SECRET"],
region: "us-east-1",
}
config.fog_directory = ENV['AWS_BUCKET_NAME']
config.fog_directory = ENV["AWS_BUCKET_NAME"]
end
end

View file

@ -0,0 +1,14 @@
class CreateBadges < ActiveRecord::Migration[5.1]
def change
create_table :badges do |t|
t.string :title, null: false
t.string :slug, null: false
t.string :description, null: false
t.string :badge_image
t.timestamps
end
add_index :badges, :title, unique: true
end
end

View file

@ -0,0 +1,13 @@
class CreateBadgeAchievements < ActiveRecord::Migration[5.1]
def change
create_table :badge_achievements do |t|
t.references :user, foreign_key: true, null: false
t.integer :rewarder_id
t.references :badge, foreign_key: true, null: false
t.timestamps
end
add_index :badge_achievements, [:user_id, :badge_id]
end
end

View file

@ -116,6 +116,27 @@ ActiveRecord::Schema.define(version: 20180502174301) do
t.index ["user_id"], name: "index_articles_on_user_id"
end
create_table "badge_achievements", force: :cascade do |t|
t.bigint "badge_id", null: false
t.datetime "created_at", null: false
t.integer "rewarder_id"
t.datetime "updated_at", null: false
t.bigint "user_id", null: false
t.index ["badge_id"], name: "index_badge_achievements_on_badge_id"
t.index ["user_id", "badge_id"], name: "index_badge_achievements_on_user_id_and_badge_id"
t.index ["user_id"], name: "index_badge_achievements_on_user_id"
end
create_table "badges", force: :cascade do |t|
t.string "badge_image"
t.datetime "created_at", null: false
t.string "description", null: false
t.string "slug", null: false
t.string "title", null: false
t.datetime "updated_at", null: false
t.index ["title"], name: "index_badges_on_title", unique: true
end
create_table "blocks", id: :serial, force: :cascade do |t|
t.text "body_html"
t.text "body_markdown"
@ -652,6 +673,8 @@ ActiveRecord::Schema.define(version: 20180502174301) do
t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
end
add_foreign_key "badge_achievements", "badges"
add_foreign_key "badge_achievements", "users"
add_foreign_key "messages", "chat_channels"
add_foreign_key "messages", "users"
end

6
spec/factories/badges.rb Normal file
View file

@ -0,0 +1,6 @@
FactoryBot.define do
factory :badge do
title { Faker::Overwatch.quote }
description { Faker::Lorem.sentence }
end
end

View file

@ -0,0 +1,21 @@
require "rails_helper"
RSpec.describe BadgeAchievement, type: :model do
let(:user) { create(:user) }
let(:badge) { create(:badge) }
describe "validations" do
subject { BadgeAchievement.create(user_id: user.id, badge_id: badge.id) }
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:badge) }
it { is_expected.to belong_to(:rewarder).class_name("User") }
end
it "allow duplicate badges" do
BadgeAchievement.create(user_id: user.id, badge_id: badge.id, rewarder_id: create(:user).id)
expect do
BadgeAchievement.create!(user_id: user.id, badge_id: badge.id, rewarder_id: create(:user).id)
end.not_to raise_error
end
end

13
spec/models/badge_spec.rb Normal file
View file

@ -0,0 +1,13 @@
require "rails_helper"
RSpec.describe Badge, type: :model do
describe "validations" do
subject { Badge.create(title: Faker::Overwatch.quote, description: Faker::Lorem.sentence) }
it { is_expected.to have_many(:users).through(:badge_achievements) }
it { is_expected.to have_many(:badge_achievements) }
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to validate_presence_of(:description) }
it { is_expected.to validate_uniqueness_of(:title) }
end
end

View file

@ -9,15 +9,17 @@ RSpec.describe User, type: :model do
let(:org) { create(:organization) }
it { is_expected.to have_many(:articles) }
it { is_expected.to have_many(:reactions) }
it { is_expected.to have_many(:comments) }
it { is_expected.to have_many(:identities) }
it { is_expected.to have_many(:badge_achievements) }
it { is_expected.to have_many(:badges).through(:badge_achievements) }
it { is_expected.to have_many(:collections) }
it { is_expected.to have_many(:tweets) }
it { is_expected.to have_many(:notifications) }
it { is_expected.to have_many(:mentions) }
it { is_expected.to have_many(:comments) }
it { is_expected.to have_many(:email_messages).class_name("Ahoy::Message") }
it { is_expected.to have_many(:identities) }
it { is_expected.to have_many(:mentions) }
it { is_expected.to have_many(:notes) }
it { is_expected.to have_many(:notifications) }
it { is_expected.to have_many(:reactions) }
it { is_expected.to have_many(:tweets) }
it { is_expected.to validate_uniqueness_of(:username).case_insensitive }
it { is_expected.to validate_uniqueness_of(:github_username).allow_blank }
it { is_expected.to validate_uniqueness_of(:twitter_username).allow_blank }