Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Commit

Permalink
Rename "Page" to "Post"
Browse files Browse the repository at this point in the history
Naming is one of the hardest things in computer science: Using a „Page“
model is suboptimal, because it conflicts with Kaminari „paginator“
concept and Capybara #page method
  • Loading branch information
ledermann committed May 16, 2017
1 parent 6d981f1 commit 06f6185
Show file tree
Hide file tree
Showing 50 changed files with 399 additions and 393 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
[![Greenkeeper badge](https://badges.greenkeeper.io/ledermann/docker-rails.svg)](https://greenkeeper.io/)
[![](https://images.microbadger.com/badges/image/ledermann/docker-rails.svg)](https://microbadger.com/images/ledermann/docker-rails)

Simple Rails 5.1 application to demonstrate using Docker for production deployment. The application is a very simple kind of CMS (content management system) allowing to manage pages. Beside the boring [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) functionality it demonstrates the following features:
Simple Rails 5.1 application to demonstrate using Docker for production deployment. The application is a very simple kind of CMS (content management system) allowing to manage posts. Beside the boring [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) functionality it demonstrates the following features:

- Auto refresh via [ActionCable](https://github.com/rails/rails/tree/master/actioncable): If a displayed page gets changed by another user/instance, it refreshes automatically using the publish/subscribe pattern
- Full text search via [Elasticsearch](https://www.elastic.co/products/elasticsearch) and the [Searchkick](https://github.com/ankane/searchkick) gem to find page content
- Auto refresh via [ActionCable](https://github.com/rails/rails/tree/master/actioncable): If a displayed post gets changed by another user/instance, it refreshes automatically using the publish/subscribe pattern
- Full text search via [Elasticsearch](https://www.elastic.co/products/elasticsearch) and the [Searchkick](https://github.com/ankane/searchkick) gem to find post content
- Background jobs with [ActiveJob](https://github.com/rails/rails/tree/master/activejob) and the [Sidekiq](http://sidekiq.org/) gem (to handle full text indexing)
- PDF export with [wkhtmltopdf](http://wkhtmltopdf.org/) and the [WickedPDF](https://github.com/mileszs/wicked_pdf) gem
- Infinitive scrolling (using the [Kaminari](https://github.com/kaminari/kaminari) gem and some Javascript)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
$(document).on 'turbolinks:load', ->
page_id = $('article').data('cable-page-id')
post_id = $('article').data('cable-post-id')

if page_id
App.updates = App.cable.subscriptions.create { channel: "PageUpdateChannel", page_id: page_id },
if post_id
App.updates = App.cable.subscriptions.create { channel: "PostUpdateChannel", post_id: post_id },
connected: ->
# Called when the subscription is ready for use on the server
console.log "Connected to " + App.updates.identifier
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class @PagesIndex
class @PostsIndex
constructor: ->
# Make rows (means: cells with class js-row-link) clickable
$('.table tr[data-href] > td.js-row-link')
Expand Down
14 changes: 0 additions & 14 deletions app/channels/page_update_channel.rb

This file was deleted.

14 changes: 14 additions & 0 deletions app/channels/post_update_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class PostUpdateChannel < ApplicationCable::Channel
def subscribed
stop_all_streams

if params[:post_id]
post = Post.find(params[:post_id])
stream_for post
end
end

def unsubscribed
stop_all_streams
end
end
Original file line number Diff line number Diff line change
@@ -1,100 +1,100 @@
class PagesController < ApplicationController
before_action :set_page, only: [:show, :edit, :update, :destroy]
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]

# GET /pages
# GET /pages.json
# GET /posts
# GET /posts.json
def index
@pages = if search_string
Page.search search_string,
@posts = if search_string
Post.search search_string,
fields: [ 'title^10', 'content' ],
match: :word_start,
misspellings: { prefix_length: 2 },
highlight: { tag: '<strong>' },
page: params[:page],
per_page: 25
else
Page.order(updated_at: :desc).
Post.order(updated_at: :desc).
page(params[:page]).
per(25)
end

respond_to do |format|
format.js { render 'kaminari/infinite-scrolling', locals: { objects: @pages } }
format.js { render 'kaminari/infinite-scrolling', locals: { objects: @posts } }
format.html
end
end

# GET /pages/1
# GET /pages/1.json
# GET /pages/1.pdf
# GET /posts/1
# GET /posts/1.json
# GET /posts/1.pdf
def show
respond_to do |format|
format.html
format.json
format.pdf { render pdf: @page.title,
format.pdf { render pdf: @post.title,
disposition: 'inline',
show_as_html: params[:debug].present? }
end
end

# GET /pages/new
# GET /posts/new
def new
@page = Page.new
@post = Post.new
end

# GET /pages/1/edit
# GET /posts/1/edit
def edit
end

# POST /pages
# POST /pages.json
# POST /posts
# POST /posts.json
def create
@page = Page.new(page_params)
@post = Post.new(post_params)

respond_to do |format|
if @page.save
format.html { redirect_to @page, notice: 'Page was successfully created.' }
format.json { render :show, status: :created, location: @page }
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @page.errors, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /pages/1
# PATCH/PUT /pages/1.json
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if @page.update(page_params)
format.html { redirect_to @page, notice: 'Page was successfully updated.' }
format.json { render :show, status: :ok, location: @page }
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @page.errors, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

# DELETE /pages/1
# DELETE /pages/1.json
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
@page.destroy!
@post.destroy!
respond_to do |format|
format.html { redirect_to pages_url, notice: 'Page was successfully destroyed.' }
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_page
@page = Page.find(params[:id])
def set_post
@post = Post.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def page_params
params.require(:page).permit(:title, :content)
def post_params
params.require(:post).permit(:title, :content)
end

helper_method def search_string
Expand Down
7 changes: 0 additions & 7 deletions app/jobs/page_relay_job.rb

This file was deleted.

7 changes: 7 additions & 0 deletions app/jobs/post_relay_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class PostRelayJob < ApplicationJob
queue_as :default

def perform(post)
PostUpdateChannel.broadcast_to post, html: PostsController.render(action: 'show', layout: false, assigns: { post: post })
end
end
6 changes: 3 additions & 3 deletions app/models/page.rb → app/models/post.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
class Page < ApplicationRecord
class Post < ApplicationRecord
validates_presence_of :title, :content

searchkick word_start: [ :title, :content ],
highlight: [ :title, :content ],
callbacks: :async

after_commit on: :update do |page|
PageRelayJob.perform_later(page)
after_commit on: :update do |post|
PostRelayJob.perform_later(post)
end
end
2 changes: 1 addition & 1 deletion app/views/layouts/application.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ html[lang="en"]
li
= link_to 'Sidekiq', sidekiq_web_path, data: { turbolinks: 'false' }
li
= form_with url: pages_path, local: true, method: "get", class: 'navbar-form', id: 'search' do
= form_with url: posts_path, local: true, method: "get", class: 'navbar-form', id: 'search' do
.input-group
= text_field_tag :q, params[:q], placeholder: "Search", class: 'form-control'
.input-group-btn
Expand Down
13 changes: 0 additions & 13 deletions app/views/pages/_page.html.slim

This file was deleted.

2 changes: 0 additions & 2 deletions app/views/pages/_page.json.jbuilder

This file was deleted.

2 changes: 0 additions & 2 deletions app/views/pages/edit.html.slim

This file was deleted.

1 change: 0 additions & 1 deletion app/views/pages/index.json.jbuilder

This file was deleted.

2 changes: 0 additions & 2 deletions app/views/pages/new.html.slim

This file was deleted.

1 change: 0 additions & 1 deletion app/views/pages/show.json.jbuilder

This file was deleted.

10 changes: 0 additions & 10 deletions app/views/pages/show.pdf.slim

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
= form_with model: page, local: true do |f|
- if page.errors.any?
= form_with model: post, local: true do |f|
- if post.errors.any?
#error_explanation.text-danger
h2
= pluralize(page.errors.count, "error")
| prohibited this page from being saved:
= pluralize(post.errors.count, "error")
| prohibited this post from being saved:
ul.list-unstyled
- page.errors.full_messages.each do |message|
- post.errors.full_messages.each do |message|
li
= message
.form-group
Expand Down
13 changes: 13 additions & 0 deletions app/views/posts/_post.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
tr[data-href=url_for(post)]
td.js-row-link
- if search_string && post.search_highlights[:title]
== post.search_highlights[:title]
- else
= post.title.truncate(80)
td.js-row-link.text-muted
- if search_string && post.search_highlights[:content]
== post.search_highlights[:content]
- else
= post.content.truncate(100)
td.js-row-link.text-right
= time_tag post.updated_at
2 changes: 2 additions & 0 deletions app/views/posts/_post.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
json.extract! post, :id, :title, :content, :created_at, :updated_at
json.url post_url(post, format: :json)
2 changes: 2 additions & 0 deletions app/views/posts/edit.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
h1 Editing Post
= render 'form', post: @post
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
.jumbotron
.row
.col-sm-10
h1 Pages
h1 Posts
p.lead Just some plain old CRUD operations
a.btn.btn-lg.btn-success[href=new_page_path role="button"] Add new Page
a.btn.btn-lg.btn-success[href=new_post_path role="button"] Add new Post
.col-sm-2.text-right.hidden-xs
= icon('file-text-o', class: 'fa-5x')

- if search_string
.alert.alert-info
| Pages matching
| Posts matching
'
strong= search_string
'
| only

p.small.text-muted.text-right#page-count
= pluralize @pages.total_count, 'Page'
p.small.text-muted.text-right#post-count
= pluralize @posts.total_count, 'Post'

table.table.table-striped
thead
Expand All @@ -25,6 +25,6 @@ table.table.table-striped
th Content
th.text-right Updated
tbody#js-infinite-scrolling
= render @pages
= render @posts

= render 'kaminari/paging', objects: @pages
= render 'kaminari/paging', objects: @posts
1 change: 1 addition & 0 deletions app/views/posts/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.array! @posts, partial: 'posts/post', as: :post
2 changes: 2 additions & 0 deletions app/views/posts/new.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
h1 New Post
= render 'form', post: @post
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
article data-cable-page-id=@page.id
article data-cable-post-id=@post.id
header.row
.col-sm-11.col-sm-offset-1
h1
= @page.title
= @post.title

p.text-muted
| Updated
'
= time_tag(@page.updated_at)
= time_tag(@post.updated_at)

.row
.col-sm-1
.btn-group-vertical[role='group']
= link_to page_path(@page, format: 'pdf'), class: 'btn btn-default btn-lg', data: { turbolinks: 'false' }, title: 'Export Page as PDF' do
= link_to post_path(@post, format: 'pdf'), class: 'btn btn-default btn-lg', data: { turbolinks: 'false' }, title: 'Export Post as PDF' do
= icon('file-pdf-o')

= link_to edit_page_path(@page), class: 'btn btn-default btn-lg', title: 'Edit Page' do
= link_to edit_post_path(@post), class: 'btn btn-default btn-lg', title: 'Edit Post' do
= icon('pencil')

= link_to @page, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-lg', role: 'button', title: 'Destroy' do
= link_to @post, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-lg', role: 'button', title: 'Destroy' do
= icon('trash')

.col-sm-11
= simple_format h(@page.content)
= simple_format h(@post.content)
1 change: 1 addition & 0 deletions app/views/posts/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.partial! "posts/post", post: @post
Loading

0 comments on commit 06f6185

Please sign in to comment.