From 95fbd10153035043318fcc08b92988c817fc3301 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 29 Jun 2017 23:39:56 +0300 Subject: [PATCH] Friendly urls for tracks Don't use tracks ids in urls Add short_name to tracks and use that in urls as the identifier --- app/controllers/admin/tracks_controller.rb | 4 +- app/models/track.rb | 6 +++ app/views/admin/tracks/_form.html.haml | 3 +- app/views/admin/tracks/index.html.haml | 9 +++-- .../versions/_object_desc_and_link.html.haml | 2 +- ...20170629162450_add_short_name_to_tracks.rb | 39 +++++++++++++++++++ db/schema.rb | 3 +- spec/factories/tracks.rb | 1 + spec/features/tracks_spec.rb | 2 + 9 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20170629162450_add_short_name_to_tracks.rb diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 2df7db67..4fc9d9c7 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -2,7 +2,7 @@ module Admin class TracksController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true - load_and_authorize_resource through: :program + load_and_authorize_resource through: :program, find_by: :short_name def index; end @@ -53,7 +53,7 @@ module Admin private def track_params - params.require(:track).permit(:name, :description, :color) + params.require(:track).permit(:name, :description, :color, :short_name) end end end diff --git a/app/models/track.rb b/app/models/track.rb index 1d94f7d5..d3502bb0 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -7,6 +7,12 @@ class Track < ActiveRecord::Base before_create :generate_guid validates :name, presence: true validates :color, format: /\A#[0-9A-F]{6}\z/ + validates :short_name, + presence: true, + format: /\A[a-zA-Z0-9_-]*\z/, + uniqueness: { + scope: :program + } before_validation :capitalize_color diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index 579d263d..c3c7cf26 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -8,8 +8,9 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track.short_name))) do |f| = f.input :name + = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index f2de8a38..f9ed9036 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -9,6 +9,7 @@ %table.table.table-hover#tracks %thead %th Name + %th Short name %th Description %th Color %th Actions @@ -16,8 +17,10 @@ - @tracks.each do |track| %tr %td - = link_to(admin_conference_program_track_path(@conference.short_title, track)) do + = link_to(admin_conference_program_track_path(@conference.short_title, track.short_name)) do = track.name + %td + = track.short_name %td %p = truncate(track.description) @@ -26,9 +29,9 @@ = track.color %td .btn-group{role: "group"} - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.id), + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.short_name), method: :get, class: 'btn btn-primary' - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track.id), + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track.short_name), method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } .row diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 14b1f2fc..83542ef1 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -94,7 +94,7 @@ = 'track' - track = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, track.name, - admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: track.try(:short_name)) - when 'EventType' = 'event type' diff --git a/db/migrate/20170629162450_add_short_name_to_tracks.rb b/db/migrate/20170629162450_add_short_name_to_tracks.rb new file mode 100644 index 00000000..cbc6b431 --- /dev/null +++ b/db/migrate/20170629162450_add_short_name_to_tracks.rb @@ -0,0 +1,39 @@ +class AddShortNameToTracks < ActiveRecord::Migration + class TmpProgram < ActiveRecord::Base + self.table_name = 'programs' + end + + class TmpTrack < ActiveRecord::Base + self.table_name = 'tracks' + end + + def change + add_column :tracks, :short_name, :string + + TmpTrack.reset_column_information + + TmpProgram.find_each do |program| + # Keeps count of how many times we've encountered a short_name + track_name_counter = {} + + TmpTrack.where(program_id: program.id).find_each do |track| + # Replace spaces with undercores and remove the non alphanumeric characters that aren't underscores or dashes + short_name = track.name.tr(' ', '_').tr('^a-zA-Z0-9_-', '') + + # If we've seen that short_name before then add the counter in the end to avoid collisions + if track_name_counter[short_name] + track_name_counter[short_name] += 1 + short_name += "_#{track_name_counter[short_name]}" + else + # Initialize the counter + track_name_counter[short_name] = 0 unless track_name_counter[short_name] + end + + track.short_name = short_name + track.save! + end + end + + change_column_null :tracks, :short_name, false + end +end diff --git a/db/schema.rb b/db/schema.rb index 348f6170..2e2fb088 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170603095900) do +ActiveRecord::Schema.define(version: 20170629162450) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -485,6 +485,7 @@ ActiveRecord::Schema.define(version: 20170603095900) do t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" + t.string "short_name", null: false end create_table "users", force: :cascade do |t| diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index 1b7f8083..4334cb4c 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -3,6 +3,7 @@ FactoryGirl.define do name { Faker::Commerce.department(2, true) } description { Faker::Lorem.sentence } color { Faker::Color.hex_color } + short_name { SecureRandom.urlsafe_base64(5) } program end end diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index d1972075..3538a6d7 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -14,6 +14,7 @@ feature Track do click_link 'New Track' fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' page.find('#track_color').set('#B94D4D') fill_in 'track_description', with: 'Events about our Linux distribution' click_button 'Create Track' @@ -50,6 +51,7 @@ feature Track do click_link 'Edit' fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' page.find('#track_color').set('#B94D4D') fill_in 'track_description', with: 'Events about our Linux distribution' click_button 'Update Track'