Merge branch 'atomaka/feature/subcreddit' into 'master'

Add subcreddits

Reddit has subreddits. We have subcreddits.  Get it?  Because we're subcreddit.

See merge request !8
This commit is contained in:
Andrew Tomaka 2015-07-13 17:04:45 -04:00
commit 2cac3d9f1c
22 changed files with 450 additions and 22 deletions

View file

@ -50,4 +50,5 @@ group :test do
gem 'capybara-webkit' gem 'capybara-webkit'
gem 'shoulda' gem 'shoulda'
gem 'simplecov', require: false gem 'simplecov', require: false
gem 'timecop'
end end

View file

@ -338,6 +338,7 @@ GEM
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (1.4.1) tilt (1.4.1)
timecop (0.7.4)
tzinfo (1.2.2) tzinfo (1.2.2)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (2.7.1) uglifier (2.7.1)
@ -392,6 +393,7 @@ DEPENDENCIES
spring spring
spring-commands-rspec spring-commands-rspec
sqlite3 sqlite3
timecop
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
BUNDLED WITH BUNDLED WITH

View file

@ -1,3 +1,3 @@
// Place all the styles related to the Tests controller here. // Place all the styles related to the Subcreddits controller here.
// They will automatically be included in application.css. // They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/ // You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,50 @@
class SubcredditsController < ApplicationController
before_filter :set_subcreddit, only: [:show, :edit, :update]
def index
@subcreddits = Subcreddit.all
end
def show
end
def new
@subcreddit = Subcreddit.new
end
def create
@subcreddit = Subcreddit.new(create_subcreddit_params)
@subcreddit.owner = current_user
if @subcreddit.save
redirect_to @subcreddit, notice: 'Subcreddit was created!'
else
render :new
end
end
def edit
end
def update
if @subcreddit.update(update_subcreddit_params)
redirect_to @subcreddit, notice: 'Subcreddit was updated!'
else
render :edit
end
end
private
def create_subcreddit_params
params.require(:subcreddit).permit(:name)
end
def update_subcreddit_params
params.require(:subcreddit).permit(:closed)
end
def set_subcreddit
@subcreddit = Subcreddit.find_by_slug(params[:id])
end
end

View file

@ -1,7 +0,0 @@
class TestsController < ApplicationController
def index
end
def show
end
end

53
app/models/subcreddit.rb Normal file
View file

@ -0,0 +1,53 @@
RESERVED_SLUGS = %w(new edit)
class Subcreddit < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
attr_accessor :closed
before_save :set_slug
before_save :set_closed_at
validates :name,
presence: true,
format: /\A(?! )[a-z0-9 ]*(?<! )\z/i,
uniqueness: { case_sensitive: false },
length: { minimum: 3, maximum: 21 }
validate :slug_is_not_a_route
validates :closed,
format: /\A[01]?\z/
def to_param
self.slug
end
def closed?
self.closed_at != nil
end
private
def set_slug
self.slug = sluggify_name
end
def sluggify_name
self.name.downcase.tr(' ', '_')
end
def set_closed_at
if closed == '1' && closed_at == nil
self.closed_at = Time.now
elsif closed == '0' && closed_at != nil
self.closed_at = nil
end
end
def slug_is_not_a_route
if RESERVED_SLUGS.include?(sluggify_name)
errors.add(:name, 'cannot be a reserved keyword')
end
end
end

View file

@ -8,10 +8,11 @@
span.icon-bar span.icon-bar
= link_to 'Creddit', root_path, class: 'navbar-brand' = link_to 'Creddit', root_path, class: 'navbar-brand'
.collapse.navbar-collapse .collapse.navbar-collapse
ul.nav.navbar-nav.navbar-right ul.nav.navbar-nav
- if logged_in? li= link_to 'Subcreddits', subcreddits_path
li= link_to 'Sign Out', signout_path ul.nav.navbar-nav.navbar-right
- else - if logged_in?
li= link_to 'Create Account', signup_path li= link_to 'Sign Out', signout_path
li= link_to 'Sign In', signin_path - else
li= link_to 'Create Account', signup_path
li= link_to 'Sign In', signin_path

View file

@ -0,0 +1,8 @@
= simple_form_for subcreddit do |f|
.form-inputs
- if subcreddit.new_record?
= f.input :name
- unless subcreddit.new_record?
= f.input :closed, as: :boolean, input_html: { checked: subcreddit.closed? }
.form-actions
= f.button :submit

View file

@ -0,0 +1 @@
== render 'form', subcreddit: @subcreddit

View file

@ -0,0 +1,7 @@
= link_to 'Create', new_subcreddit_path
ul
- @subcreddits.each do |subcreddit|
li
= link_to subcreddit.name, subcreddit
== " (#{link_to 'Edit', edit_subcreddit_path(subcreddit)})"

View file

@ -0,0 +1 @@
== render 'form', subcreddit: @subcreddit

View file

@ -0,0 +1,3 @@
h1= @subcreddit.name
- if @subcreddit.closed?
= "Board has been closed"

View file

View file

@ -1 +0,0 @@
= 'tests#index'

View file

@ -1 +0,0 @@
= 'tests#show'

View file

@ -1,12 +1,11 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :tests, only: [:index, :show]
get 'signup', to: 'users#new', as: :signup get 'signup', to: 'users#new', as: :signup
get 'signin', to: 'user_sessions#new', as: :signin get 'signin', to: 'user_sessions#new', as: :signin
get 'signout', to: 'user_sessions#destroy', as: :signout get 'signout', to: 'user_sessions#destroy', as: :signout
resources :users, only: [:new, :create] resources :subcreddits, path: 'c', except: [:destroy]
resources :user_sessions, only: [:new, :create, :destroy] resources :user_sessions, only: [:new, :create, :destroy]
resources :users, only: [:new, :create]
root to: 'tests#index' root to: 'subcreddits#index'
end end

View file

@ -0,0 +1,12 @@
class CreateSubcreddits < ActiveRecord::Migration
def change
create_table :subcreddits do |t|
t.references :owner, index: true, foreign_key: true
t.string :name
t.string :slug
t.datetime :closed_at
t.timestamps null: false
end
end
end

View file

@ -11,7 +11,18 @@
# #
# 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: 20150710040354) do ActiveRecord::Schema.define(version: 20150713045745) do
create_table "subcreddits", force: :cascade do |t|
t.integer "owner_id"
t.string "name"
t.string "slug"
t.datetime "closed_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "subcreddits", ["owner_id"], name: "index_subcreddits_on_owner_id"
create_table "user_sessions", force: :cascade do |t| create_table "user_sessions", force: :cascade do |t|
t.integer "user_id" t.integer "user_id"

View file

@ -0,0 +1,156 @@
require 'rails_helper'
describe SubcredditsController, type: :controller do
let!(:user) { build(:user) }
let(:data) do
{
name: 'Testing Subcreddit 1'
}
end
before(:each) do
allow_any_instance_of(ApplicationController)
.to receive(:current_user).and_return(user)
end
describe '#index' do
let!(:subcreddits) { 3.times.collect { create(:subcreddit) } }
it 'should render :index' do
get :index
expect(response).to render_template(:index)
end
it 'should assign all Subcreddits to @subcreddits' do
get :index
expect(assigns(:subcreddits)).to eq(subcreddits)
end
end
describe '#show' do
let(:subcreddit) { create(:subcreddit) }
before(:each) { get :show, id: subcreddit }
it 'should render :show' do
expect(response).to render_template(:show)
end
it 'should assign the Subcreddit to @subcreddit' do
expect(assigns(:subcreddit)).to eq(subcreddit)
end
end
describe '#new' do
it 'should render :new' do
get :new
expect(response).to render_template(:new)
end
it 'should assign new Subcreddit to @subcreddit' do
get :new
expect(assigns(:subcreddit)).to be_a_new(Subcreddit)
end
end
describe '#create' do
context 'with valid data' do
it 'should create a subcreddit' do
expect { post :create, subcreddit: data }
.to change(Subcreddit, :count).by(1)
end
it 'should redirect to new subcreddit page index' do
expect(post :create, subcreddit: data)
.to redirect_to(assigns(:subcreddit))
end
it 'should send a notice flash message' do
post :create, subcreddit: data
expect(flash[:notice]).to be_present
end
end
context 'with invalid data' do
before(:each) { data['name'] = 'Bad name ' }
it 'should not create a subcreddit' do
expect { post :create, subcreddit: data }
.to change(Subcreddit, :count).by(0)
end
it 'should render :new' do
post :create, subcreddit: data
expect(response).to render_template(:new)
end
end
end
describe '#edit' do
context 'with valid subcreddit' do
let(:subcreddit) { create(:subcreddit) }
it 'should assign @subcreddit to the existing subcreddit' do
get :edit, id: subcreddit
expect(assigns(:subcreddit)).to eq(subcreddit)
end
it 'should render :edit' do
get :edit, id: subcreddit
expect(response).to render_template(:edit)
end
end
end
describe '#update' do
let(:subcreddit) { create(:subcreddit) }
let(:data) do
{
closed: '1'
}
end
context 'wth valid data' do
it 'should assign @subcreddit to the existing subcreddit' do
put :update, id: subcreddit, subcreddit: data
expect(assigns(:subcreddit)).to eq(subcreddit)
end
it 'should update the subcreddit' do
put :update, id: subcreddit, subcreddit: data
subcreddit.reload
expect(subcreddit.closed_at).to_not eq(nil)
end
it 'should redirect to the subcreddit' do
put :update, id: subcreddit, subcreddit: data
expect(response).to redirect_to(subcreddit_url(subcreddit))
end
it 'should display a notice flash message' do
put :update, id: subcreddit, subcreddit: data
expect(flash[:notice]).to be_present
end
end
context 'with invalid data' do
before(:each) { data[:closed] = 'bad' }
it 'should render :edit' do
put :update, id: subcreddit, subcreddit: data
expect(response).to render_template(:edit)
end
end
end
end

View file

@ -0,0 +1,6 @@
FactoryGirl.define do
factory :subcreddit do
owner { create(:user) }
name { Faker::Team.name.first(21) } # 21 is the max length...brittle
end
end

View file

@ -0,0 +1,126 @@
require 'rails_helper'
describe Subcreddit, type: :model do
let(:subcreddit) { build(:subcreddit) }
it { should belong_to(:owner).class_name('User') }
context 'with valid data' do
it 'should be valid' do
expect(subcreddit).to be_valid
end
it 'should allow spaces in the name' do
subcreddit.name = 'Testing Spaces'
expect(subcreddit).to be_valid
end
it 'should sluggify the name' do
subcreddit.name = 'Testing Spaces 1'
subcreddit.save
expect(subcreddit.slug).to eq('testing_spaces_1')
end
it 'should set closed_at if closed is true and closed_at is nil' do
Timecop.freeze do
subcreddit.closed = '1'
subcreddit.save
expect(subcreddit.closed_at).to eq(Time.now)
end
end
it 'should not change closed_at if closed and closed_at is not nil' do
subcreddit.closed_at = Time.now - 3.days
Timecop.freeze do
subcreddit.closed = '1'
subcreddit.save
expect(subcreddit.closed_at).to_not eq(Time.now)
end
end
it 'should clear closed_at if closed is "0"' do
subcreddit.closed_at = Time.now
subcreddit.closed = '0'
subcreddit.save
expect(subcreddit.closed_at).to eq(nil)
end
end
context 'with invalid data' do
it 'should not allow a blank name' do
subcreddit.name = ''
expect(subcreddit).to be_invalid
end
it 'should not allow short names' do
subcreddit.name = 'a' * 2
expect(subcreddit).to be_invalid
end
it 'should not allow long names' do
subcreddit.name = 'a' * 22
expect(subcreddit).to be_invalid
end
it 'should only allow acceptable characters in the name' do
subcreddit.name = 'Testing!'
expect(subcreddit).to be_invalid
end
it 'should not be allowed to end with a space' do
subcreddit.name = 'Testing '
expect(subcreddit).to be_invalid
end
it 'should not be allowed to begin with a space' do
subcreddit.name = ' Testing'
expect(subcreddit).to be_invalid
end
it 'should not allow duplicate names' do
original = create(:subcreddit)
duplicate = build(:subcreddit, name: original.name)
expect(duplicate).to be_invalid
end
it 'should not allow duplicate names (case insensitive)' do
original = create(:subcreddit)
duplicate = build(:subcreddit, name: original.name.upcase)
expect(duplicate).to be_invalid
end
it 'should not use a reserved keyword' do
subcreddit.name = 'New'
expect(subcreddit).to be_invalid
end
end
context '#closed?' do
let(:subcreddit) { build(:subcreddit) }
context 'when a subcreddit is closed' do
before(:each) { subcreddit.closed_at = Time.now }
it 'should return true' do
expect(subcreddit.closed?).to be(true)
end
end
context 'when a subcreddit is open' do
it 'should return false' do
expect(subcreddit.closed?).to be(false)
end
end
end
end