Skip to content

nacyot/vsns

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

vsns

: Dev.Study - Official VSNS Repository since 2013.9.1

2013๋…„ 9์›” 18์ผ => rack-cors ์ ฌ์ถ”๊ฐ€ํ•จ

  • Gemfile ์ถ”๊ฐ€

    gem 'rack-cors', :require => 'rack/cors' by hschoi
    
  • config/application.rb

    config.middleware.use Rack::Cors do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end
    

2013๋…„ 9์›” 12์ผ => ๋‚˜๋จธ์ง€ turbolinks ๋ฌธ์ œํ•ด๊ฒฐ ํ•จ. hschoi

  • items.js.coffee
$(document).on 'click', '.add_a_comment_link', ->
  $(this).parent().parent().next().next().slideToggle()
  false

$(document).on 'click', '.show_comments_link', ->
  if $(this).hasClass('enabled')
    $(this).next().slideToggle()  

initTooltip = ->
  $('.thumbnail').tooltip
    placement: 'bottom'

$ ->
  initTooltip()
  
$(document).on 'page:load', initTooltip 
  • communities.js.coffee
$(document).on 'click', "#add_a_community_link", ->
  $(this).parent().next().slideToggle()
  false
$(document).on 'click', "#community_header_info_link", ->
  $(this).parent().parent().find('.info').slideToggle()
  false
  • User ๋ชจ๋ธ์˜ username ์†์„ฑ์˜ validation์ด presence: true ๋กœ ์ง€์ •๋˜์–ด ์žˆ์–ด username ๊ฐ’์ด nil ์ผ ๊ฒฝ์šฐ๋Š” ์—†๊ฒ ์ง€๋งŒ, ์ด์ „์˜ ์œ ์ € ๋ฐ์ดํ„ฐ์—๋Š” username ๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•จ. ๋”ฐ๋ผ์„œ, ์•„๋ž˜์™€ ๊ฐ™์ด ์กฐ์น˜ํ•จ.
<%= link_to raw("<i class='icon-user'></i> #{current_user.try(:username)}" + " <span class='caret'></span>"), '#', class:'dropdown-toggle', data:{toggle:'dropdown'} %>

2013๋…„ 9์›” 11์ผ (#2) => ์•„์žฅ์•„์žฅ ์œ ๋‹› ์ž‘์—…๋‚ด์šฉ

  • like ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด spinner ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์˜€๋‹ค๊ฐ€ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ์ด์ค€ํ—Œ๋‹˜์˜ ๋„์›€์œผ๋กœ pageless ๊ธฐ๋Šฅ ๋ฌธ์ œ์  ํ•ด๊ฒฐํ•จ

  • ๊ธฐํƒ€ ๋‚˜๋จธ์ง€ Turbolinks ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•จ.

    • app/assets/javascripts/communities.js.coffee

      ```
      $(document).on 'click', "#add_a_community_link", ->
        $(this).parent().next().slideToggle()
        false
      $(document).on 'click', "#community_header_info_link", ->
        $(this).parent().parent().find('.info').slideToggle()
        false
      ```
      
    • app/assets/javascripts/items.js.coffee

      ```
      $(document).on 'click', '.add_a_comment_link', ->
        $(this).parent().parent().next().next().slideToggle()
        false
      
      $(document).on 'click', '.show_comments_link', ->
        if $(this).hasClass('enabled')
          $(this).next().slideToggle()  
      
      initTooltip = ->
        $('.thumbnail').tooltip
          placement: 'bottom'
      
      $ ->
        initTooltip()
        
      $(document).on 'page:load', initTooltip 
      ```
      

2013๋…„ 9์›” 11์ผ (#1) => ์•„์žฅ์•„์žฅ ์œ ๋‹› ์ž‘์—…๋‚ด์šฉ

  • ์ด์ค€ํ—Œ๋‹˜์˜ ๋„์›€์œผ๋กœ pageless ๊ธฐ๋Šฅ ๋ฌธ์ œ์  ํ•ด๊ฒฐํ•จ

  • in items/index.html

    <div id='items' data-total-pages="<%= @items.total_pages %>" data-url="<%= items_path %>" data-loader-image="<%= image_path('load1.gif') %>"> 
      <%= render @items %>
    </div>
    
    <!--To apply bottom-less pagination using pageless jQuery plugin-->
    <!--Gem : pageless-rails & will_paginate-->
    <%= will_paginate @items %>
    
  • in items.js.coffee

    initPageless = ->
      $items = $('#items')
    
      # items dom ์กด์žฌ์—ฌ๋ถ€ ํ™•์ธ
      return unless $items.length
    
      # pageless ์„ค์ •์ •๋ณด dom์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ
      opts =
        totalPages  : $items.data('total-pages')
        url         : $items.data('url')
        loaderMsg   : 'Loading more pages...'
        loaderImage : $items.data('loader-image')
    
      # pageless ์‹œ์ž‘
      $items.pageless opts
    
    # pageless ์ดˆ๊ธฐํ™”
    resetPageless = ->
      $items = $('#items')
    
      return unless $items.length
    
      $.pagelessReset()
    
    $ -> 
      initPageless()
    
    # Turbolink ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•œ ์ฒ˜๋ฆฌ
    $(document).on 'page:load', initPageless
    $(document).on 'page:before-change', resetPageless # ํ™”๋ฉด ์ „ํ™˜์ „ pageless ์ดˆ๊ธฐํ™”
    

2013๋…„ 9์›” 10์ผ => ์•„์žฅ์•„์žฅ ์œ ๋‹› ์ž‘์—…๋‚ด์šฉ

  • wmd editor์˜ turbolinks ๋ฌธ์ œ๋ฅผ ์ด์ค€ํ—Œ๋‹˜์˜ ๋„์›€์„ ๋ฐ›์•„ ๊น”๋”ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜์˜€์Œ(editor.js)

    //= require wmd/wmd
    //= require wmd/showdown
    
    var initializeWMDEditor = function () {
      new WMDEditor({
        input: "item_description",
        button_bar: "editor-button-bar",
        preview: "editor-preview",
        output: "editor-output"
      });
    
      $(".wmd-help-button").html("<a id='markdown-help-link'></a>");
    
      $("#markdown-help-link").click(function(){
        $("#editor-help-panel").slideToggle('fast');
    
        return false;
      });
    };
    
    $(function () { // dom ready
      initializeWMDEditor();
    });
    
    // Turbolink ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•œ ์ฒ˜๋ฆฌ
    $(document).on('page:load', initializeWMDEditor);
    
  • ์ด์™€ ํ•จ๊ป˜ jquery.tokeninput.js ์—ญ์‹œ turbolinks ๋ฌธ์ œ๋„ ํ•ด๊ฒฐํ•˜์˜€์Œ(items.js.coffee).

    initTagInput = ->
      $tagInput = $('input[name="item[tag_list]"]')
    
      $tagInput.tokenInput "/items/tags.json",
        theme             : 'facebook'
        tokenValue        : 'name'
        allowFreeTagging  : true
        prePopulate       : $tagInput.data('tags')
    
    $ ->
      initTagInput()
    
    # Turbolink ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•œ ์ฒ˜๋ฆฌ
    $(document).on 'page:load', initTagInput
    

2013๋…„ 9์›” 10์ผ => subicura ์ž‘์—…ํ•œ ๋‚ด์šฉ

  • facebook ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ ์™€์„œ ์ตœ์ดˆ ๊ณ„์ •์ƒ์„ฑ์‹œ ์‚ฌ์šฉ
  • devise์—์„œ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋Š” ๋กœ๊ทธ์ธํ™”๋ฉด(_links.erb)๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ๋กœ๊ทธ์ธ ํผ์„ ๋ณ€๊ฒฝ
  • vsns_config.yml์„ ์„ค์ •ํŒŒ์ผ๋กœ ์‚ฌ์šฉ (ENVํ˜•์‹์˜ ๋‹จ์  ๋ณด์™„)
  • vsns_config.yml์€ ์ถ”ํ›„ ignoreํ•ด์•ผํ•จ

2013๋…„ 9์›” 9์ผ => subicura ์ž‘์—…ํ•œ ๋‚ด์šฉ

  • devise์™€ omniauth๋ฅผ ์ด์šฉํ•˜์—ฌ twitter/facebook ๋กœ๊ทธ์ธ ์—ฐ๋™
  • ๊ธฐ์กด์— ์žˆ๋˜ username column์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜์—ฌ "์‚ฌ์šฉ์ž์ด๋ฆ„"์œผ๋กœ ์‚ฌ์šฉ (unique)
  • email์„ ๋ณด์—ฌ์ฃผ๋˜ ํ™”๋ฉด์„ username์œผ๋กœ ๋ฐ”๊ฟˆ
  • email์„ ์ˆ˜์ •ํ•˜์ง€ ๋ชปํ•˜๋„๋กํ•จ (login id ์ด๋ฏ€๋กœ..)

2013๋…„ 9์›” 9์ผ => Confidence ์œ ๋‹› ์ž‘์—…๋‚ด์šฉ

  • omniauth, omniauth-github๋ฅผ ์‚ฌ์šฉํ•ด Github๋กœ ๋กœ๊ทธ์ธํ•˜๊ธฐ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • act_as_taggable_on ๋ฅผ ์‚ฌ์šฉํ•ด Tagcloud ๊ธฐ๋Šฅ์„ ์‚ฌ์ด๋ธŒ์— ์ถ”๊ฐ€
๊ด€๋ จํŒŒ์ผ
  • config/initializers/devise.rb

    • config.omniauth :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: 'user,public_repo'
  • app/controllers/omniauth_callbacks.rb

    • Github oauth callback์šฉ
  • ํšŒ์›๊ฐ€์ž…, ํšŒ์›์ •๋ณด ์ˆ˜์ • ๋ทฐ ์ˆ˜์ •

    • Github oauth ์‹œ password ํ•„๋“œ ์ œ์™ธ์ฒ˜๋ฆฌ
  • ์ƒ๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” Github๋กœ ๋กœ๊ทธ์ธ ๋งํฌ ์ถ”๊ฐ€

  • app/models/user.rb

    • omniauth ๊ด€๋ จ ์„ค์ • ๋ฐ ํด๋ž˜์Šค & ์ธ์Šคํ„ด์Šค ๋ฉ”์†Œ๋“œ ์ถ”๊ฐ€
    • omniauth๋ฅผ ํ†ตํ•ด ๋“ค์–ด์˜จ user thumbnail์„ ์ €์žฅํ•˜๋„๋ก ๊ตฌํ˜„
  • development ํ™˜๊ฒฝ annotate gem ์ถ”๊ฐ€

    • ๊ฐ model์— table schema ์ •๋ณด comment๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” gem
    • ์ฐธ๊ณ  ๋งํฌ : annotate_models
  • development & test ํ™˜๊ฒฝ dotenv-rails gem ์ถ”๊ฐ€

    • ์ฐธ๊ณ  ๋งํฌ : dotenv

    • local ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ENV ๋ฅผ rails server ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์คŒ

    • project_root/.env ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉ

    • example vsns/.env

      GITHUB_KEY=github์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ app์˜ key
      GITHUB_SECRET=github์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ app์˜ secret
      
  • app/asset/stylesheet.css.scss

    • Tag count ์— ๋”ฐ๋ผ ์ ์šฉ๋  ์Šคํƒ€์ผ ์‹œํŠธ ์ •์˜
  • app/view/layout/shared/_sidebar.html.erb

    • Tag cloud ๊ฐ€ ๋…ธ์ถœ๋  layer ์ถ”๊ฐ€
  • app/view/layout/shared/_my_tag_cloud.html.erb

    • acts_as_taggable_on์—์„œ ์ œ๊ณตํ•˜๋Š” tag_cloud ํ—ฌํผ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉ
  • app/model/user.rb

    • owned_my_tag_counts ๋ฉ”์†Œ๋“œ ์ถ”๊ฐ€
    • acts_as_taggable_on์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์•„์ดํ…œ์˜ Tag ๋ฅผ ๊ธฐ์ค€์œผ๋กœ Cloud ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ํŠน์ • ์œ ์ € ๊ธฐ์ค€์œผ๋กœ ๋ณ€๊ฒฝ
  • ํŠน์ด์‚ฌํ•ญ

    • ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ github๋กœ login์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด .envํŒŒ์ผ์— ํ•ด๋‹น ์ •๋ณด๋ฅผ ์„ธํŒ…ํ•ด์ค˜์•ผ ํ•จ
    • .env ํŒŒ์ผ์€ ๋ณด์•ˆ์ƒ gitignore์—์„œ ์ œ์™ธ์‹œํ‚ด
    • heroku deploy ์‹œ์— GITHUB_KEY์™€ GITHUB_SECRET์„ ENV๋กœ ์„ค์ •ํ•ด์ค˜์•ผํ•จ

2013๋…„ 9์›” 9์ผ (#2) => origin wmd_editor branch์— ์ถ”๊ฐ€ํ•œ ๋‚ด์šฉ

  • summernote-rails ์ ฌ์„ wmd-rails ์ ฌ์œผ๋กœ ๋Œ€์ฒดํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • wmd-rails ์ ฌ์€ wmd ๋งˆํฌ๋‹ค์šด ์—๋””ํ„ฐ๋ฅผ assets pipeline์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ ฌ์œผ๋กœ ๋งŒ๋“  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • wmd-rails ์ ฌ์„ ์‚ฌ์šฉํ•  ๋•Œ์˜ ์ฃผ์˜์ ์€ wmd/wmd.js ํŒŒ์ผ๋‚ด์˜ WMDEditor ๊ฐ์ฒด๋Š” editor-input ์†์„ฑ์œผ๋กœ ์ง€์ •๋œ DOM ๊ฐ์ฒด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํผ ๋ทฐ ํ…œํ”Œ๋ฆฟ์—์„œ๋งŒ wmd/wmd.js ํŒŒ์ผ์„ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด items ์ปจํŠธ๋กค๋Ÿฌ ์ „์šฉ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์ธ items.html.erb ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ๊ณ , ์—ฌ๊ธฐ์— editor.js ์™€ editor.css ํŒŒ์ผ์„ ํฌํ•จํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • items์˜ show ๋ทฐ ํ…œํ”Œ๋ฆฟ์—์„œ๋Š” ๋งˆํฌ๋‹ค์šด ์ปจํ…์ธ ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด wmd/showdown.js ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์€ application.js manifest ํŒŒ์ผ์— ํฌํ•จํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋Ÿฌํ•œ ์กฐ์น˜๋ฅผ ์ทจํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” manifest ํŒŒ์ผ(applicaiton.js, application.css) ํŒŒ์ผ๋‚ด์˜ require_tree . ๋ผ์ธ์„ ์ œ๊ฑฐํ•˜๊ณ  ํ•„์š”๋กœ ํ•˜๋Š” ๋ชจ๋“  ํŒŒ์ผ์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์™€ ์—ฐ๊ด€ํ•˜์—ฌ editor.js์™€ editor.css ํŒŒ์ผ์„ precompile ์‹œ์— ํฌํ•จ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด application.rb ํŒŒ์ผ์— ์ฝ”๋“œ๋ผ์ธ์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    config.assets.precompile += %w(editor.js editor.css)
    

3be2c5a30f5e6dabf097712ba7600d4774d5be01

2013๋…„ 9์›” 9์ผ => (์•„์žฅ์•„์žฅ ์œ ๋‹›) yeonsik/master branch๋ฅผ ๋จธ์ง€ํ•˜๊ณ  refactoringํ•จ.

  • commnities.html.erb์™€ _community.html.erb ํŒŒ์ผ์„ refactoringํ•˜์˜€์Šต๋‹ˆ๋‹ค.

2013๋…„ 9์›” 8์ผ => (์•„์žฅ์•„์žฅ ์œ ๋‹›) master branch์—์„œ ์ž‘์—…ํ•œ ๋‚ด์šฉ (yeonsik)

  • item๊ธ€ ์—…๋กœ๋“œํ•  ๋•Œ ์•„๋ฌด๊ฒƒ๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š๊ณ  Saveํ•˜๋ฉด @communities_joined๊ฐ€ nil๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ItemController before_filter :set_communities_joined ์˜ต์…˜์— update, create๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํƒœ๊ทธ ์ž…๋ ฅ์‹œ์— ์ž๋™์™„์„ฑ์ด ๋˜๋„๋ก ๊ฐœ์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

    Dev RuluํŒ€์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ๊ธฐ๋Šฅ์œผ๋กœ์จ jquery.tokeninput.js ์™ธ js, cssํŒŒ์ผ๋“ค์„ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

2013๋…„ 9์›” 7์ผ => summernote ์—๋””ํ„ฐ(์œ„์ง€์œ„๊ทธ ์—๋””ํ„ฐ)๋ฅผ wmd editor(๋งˆํฌ๋‹ค์šด ์—๋””ํ„ฐ)๋กœ ๊ต์ฒด

  • items ์ปจํŠธ๋กค๋Ÿฌ์˜ form ๋ทฐ์—์„œ๋Š” description ์†์„ฑ์— ๋Œ€ํ•ด์„œ ํ˜„์žฌ summernote ์œ„์ง€์œ„๊ทธ ์—๋””ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธ€์„ ์ž‘์„ฑํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๊ฒƒ์„ ๋งˆํฌ๋‹ค์šด ์—๋””ํ„ฐ์ธ wmd ์—๋””ํ„ฐ๋กœ ๊ต์ฒดํ•˜์—ฌ ๊ตฌํ˜„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์•„์žฅ์•„์žฅ ์œ ๋‹› ๋ฏธ์…˜ ์ค‘์— ํ•˜๋‚˜๋กœ ์ œ๊ฐ€ ๋ณ„๋„๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ wmd_editor๋ผ๋Š” branch๋ฅผ ๋งŒ๋“ค์–ด pushํ•ด ๋†“์•˜์Šต๋‹ˆ๋‹ค.

2013๋…„ 9์›” 6์ผ => master branch์—์„œ ์ž‘์—…ํ•œ ๋‚ด์šฉ

  • .idea ์™€ tmp ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๋ถˆํ•„์š”ํ•œ ๋””๋ ‰ํ† ๋ฆฌ๋ผ์„œ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์œ ๋‹› ๋ฆฌ๋”๊ป˜์„œ๋Š” upstream ์ด๋ผ๋Š” remote branch๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜์‹œ๊ณ  https://github.com/dev-study/vsns.git ๋กœ ์ง€์ •ํ•ด ์ฃผ์‹  ํ›„์— git pull upstream master ํ•ด ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ž‘์—… ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    vsns $> git remote add upstream https://github.com/dev-study/vsns.git
    vsns $> git checkout master
    vsns %> git pull upstream master
    
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด dev-study/vsns ์ €์žฅ์†Œ์˜ master branch๋ฅผ ๋ณธ์ธ์˜ ๋กœ์ปฌ master ๋ธŒ๋žœ์น˜๋กœ pull ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์ฃ . ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์œ ๋‹› ์ €์žฅ์†Œ๋กœ git push origin master ํ•˜์‹œ๋ฉด ์ตœ์ข…์ ์œผ๋กœ dev-study/vsns ์ €์žฅ์†Œ์˜ ์—…๋ฐ์ดํŠธ๋œ ๋‚ด์šฉ์ด ์œ ๋‹› ์ €์žฅ์†Œ๋กœ ๊ฐ€์ ธ์™€ ๋จธ์ง€ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2013๋…„ 9์›” 6์ผ => hschoi branch์„ master branch๋กœ ๋จธ์ง€ (v0.1.3)

  • 2013๋…„ 9์›” 5์ผ ์ž์ • Midnight Hangout Code Review ์—์„œ ์ง„ํ–‰๋˜์—ˆ๋˜ refactoring ๊ฒฐ๊ณผ๋ฅผ master branch ๋กœ ๋จธ์ง€ํ•˜๊ณ  git tag ๋ฅผ v0.1.3 ์œผ๋กœ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ๊ณต์ง€ํ•œ ๋ฐ”์™€ ๊ฐ™์ด ์ด์ œ(2013.9.6 06:00)๋ถ€ํ„ฐ๋Š” ๊ฐ ์œ ๋‹› ๋ฆฌ๋”๋Š” ์ด ๋ฒ„์ „(v0.1.3)์„ fork ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ ๋‹› ๋ฉค๋ฒ„๋Š” ์œ ๋‹› ๋ฆฌ๋”์˜ ์ €์žฅ์†Œ๋ฅผ git clone ํ•ฉ๋‹ˆ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด,

  1. ๊ฐ ์œ ๋‹›์˜ ๋ฆฌ๋”๋Š” dev-study/vsns ์ €์žฅ์†Œ(v0.1.3) ๋ฅผ forkํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ ๋‹› ๋ฉค๋ฒ„๋Š” ์œ ๋‹› ๋ฆฌ๋”์˜ ์ €์žฅ์†Œ๋ฅผ clone ํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด์„œ๋Š” ์ด์ค€ํ—Œ๋‹˜์ด ์˜ฌ๋ ค ์ฃผ์‹  ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด fork ๊ธฐ๋Šฅ์„ ์ดํ•ดํ•˜๋Š”๋ฐ ๋งŽ์€ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. http://blog.outsider.ne.kr/865

  2. ์œ ๋‹› ๋ฉค๋ฒ„๋“ค์€ ๊ฐ์ž์˜ branch๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋”ฉ ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค.

    $ git checkout -b [๋ณธ์ธ์˜ branch๋ช…]
    
  3. ์œ ๋‹› ๋ฉค๋ฒ„๋Š” ๋ณธ์ธ์˜ ์ฝ”๋”ฉ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด clone ๋ฐ›์•˜๋˜ ๋ฆฌ๋”์˜ ์ €์žฅ์†Œ(github ๋‚ด์˜ ๋ฆฌ๋” ์ €์žฅ์†Œ)๋กœ ์ปค๋ฐ‹๋‚ด์šฉ์„ push ํ•˜๋Š”๋ฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค.

    $ git add .
    $ git commit -m "some commit messages"
    $ git push origin [๋ณธ์ธ์˜ branch๋ช…]
    
  4. ์ด์ œ ์œ ๋‹›์˜ ๊ฐ ๋ฉค๋ฒ„๊ฐ€ ํ˜‘์—…์„ ํ†ตํ•ด์„œ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๋ฉด, ์œ ๋‹› ๋ฆฌ๋”๋Š” ์œ ๋‹›๋ฉค๋ฒ„๋“ค์˜ branch๋ฅผ ๋จธ์ง€ํ•˜๊ณ  (์ด๋•Œ ์•ฝ๊ฐ„์˜ ์ปค๋ฐ‹ ์ถฉ๋Œ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ ๋ฆฌ๋”๋Š” ์ด๋Ÿฌํ•œ ์ถฉ๋Œ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•ด์•ผ ํ•จ) ์œ ๋‹› ๋ฆฌ๋”๋Š” ์ตœ์ข… master branch ๋ฅผ pull request ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์œ ๋‹› ๋ฆฌ๋”๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค.

    $ git pull origin [์œ ๋‹›๋ฉค๋ฒ„์˜ branch๋ช…]  # ์œ ๋‹›๋ฉค๋ฒ„์˜ ์ˆ˜ ๋งŒํผ ... 
    $ git checkout master   
    $ git merge [์œ ๋‹›๋ฉค๋ฒ„์˜ branch๋ช…]   # ์œ ๋‹›๋ฉค๋ฒ„์˜ ์ˆ˜ ๋งŒํผ ...
    
  5. ๋ฉค๋ฒ„ branch์˜ ๋จธ์ง€ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์œ ๋‹› ๋ฆฌ๋”๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด git push ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    $ git push origin master
    
  6. ์ด์ œ ์œ ๋‹› ๋ฆฌ๋”๋Š” github์— ์ ‘์†ํ•˜์—ฌ ๋ณธ์ธ์˜ ๊ณ„์ •์œผ๋กœ forkํ•œ dev-study/vsns ์ €์žฅ์†Œ๋กœ PULL REQUEST ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ๊นŒ์ง€์˜ ์ž‘์—…์€ ๊ฐ ์œ ๋‹›์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  7. ์ด๋ ‡๊ฒŒ 8๊ฐœ์˜ ์œ ๋‹›์—์„œ pull request ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ปค๋ฐ‹ํ„ฐ๋กœ ์ง€์ •๋œ ๋ฉค๋ฒ„๋“ค์€ pull request ์ปค๋ฐ‹๋“ค์„ ๊ฒ€ํ† ํ•˜๊ณ  ์ตœ์ข… master ๋ฒ„์ „์œผ๋กœ merge ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  8. ์ ˆ์ฐจ์ƒ์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จ๋˜์‹œ๋ฉด ์–ธ์ œ๋“ ์ง€ ์—ฐ๋ฝ์„ ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

2013๋…„ 9์›” 2์ผ => ๋ช‡๊ฐ€์ง€ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • ์ตœ์ข… tag ๋ฒ„์ „์€ v0.1.2 ์ž…๋‹ˆ๋‹ค. v0.1.1 ๋ฒ„์ „์— ๋ฒ„๊ทธ์ˆ˜์ •ํ•œ ๊ฒƒ์ด ๋ฐ˜์˜์ด ์•ˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

๋‹น๋ถ„๊ฐ„ VSNS์˜ ๊ธฐ๋Šฅ์ถ”๊ฐ€๋Š” ์—†์Šต๋‹ˆ๋‹ค.

  • ์ตœ์ข… tag ๋ฒ„์ „์€ v0.1.1 ์ž…๋‹ˆ๋‹ค.

2013๋…„ 9์›” 1์ผ => Community ๊ด€๋ จ ๊ธฐ๋Šฅ ๋ณด์™„ (bbugguj)

1. ItemController์˜ show, edit, new ์•ก์…˜์—์„œ before_filter๋ฅผ ํ†ตํ•ด set_communities_joined๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•จ
  • ์ด์œ : layouts/shared/_my_communities.html.erb์—์„œ @communities_joined๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ community ๋ชฉ๋ก์„ ๊ตฌ์„ฑํ•˜๋Š”๋ฐ, show.html, edit.html, new.html ์—์„œ๋Š” @communities_joined๊ฐ€ nil์ด์–ด์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
  • ๊ด€๋ จ ํŒŒ์ผ
  • controllers/items_controller.rb
2. Community ์ถ”๊ฐ€ ํ›„ My Join Communities ์˜ count๋ฅผ ๋ณ€๊ฒฝํ•˜๋„๋ก ์ˆ˜์ •
  • ๊ด€๋ จ ํŒŒ์ผ
  • view/communities/create.js.erb
  • view/layouts/shared/_my_communities.html.erb
  • controllers/communities_controller.rb
3. Community ์ตœ์ดˆ ์ถ”๊ฐ€์‹œ My Join Communities ๋ชฉ๋ก์— ๋ฐ˜์˜ ์•ˆ๋˜๋Š” ๋ถ€๋ถ„ ์ˆ˜์ •
  • ์ˆ˜์ •๋ถ€๋ถ„: @communities_joined.size๊ฐ€ 0์ธ ๊ฒฝ์šฐ๋„ ul ์˜์—ญ์„ ์ƒ์„ฑํ•˜๋„๋ก ์ˆ˜์ •.

  • ์ด์œ : view/communities/create.js.erb์—์„œ๋Š” #community_list ์˜์—ญ์— ์ƒˆ๋กœ ์ƒ์„ฑํ•œ cummunity๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ. communities.size๊ฐ€ 0์ธ ๊ฒฝ์šฐ์—๋„ #community_list ์˜์—ญ์„ ์ƒ์„ฑํ•ด์ฃผ์–ด์•ผ ์ด ๋ถ€๋ถ„์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•จ

  • ๊ด€๋ จ ํŒŒ์ผ

  • view/layouts/shared/_my_communities.html.erb

Dev.Study VSNS Project v0.1.0 just pushed !!!

: as of 2013๋…„ 9์›” 1์ผ, 18:45am

  • ์ด์ œ Big Pie ํŒ€ํ”„๋กœ์ ํŠธ๋กœ ๊ณต๋™(?) ๊ฐœ๋ฐœ๋œ vsns Blog project๋ฅผ master branch์— ๋จธ์ง€ํ•˜๊ณ  v0.1.0 ํƒœ๊ทธ๋ฅผ ๋‹ฌ์•„์„œ github์— pushํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ์ƒ๋‹น ๋ถ€๋ถ„์˜ refactoring ๊ณผ์ •์ด ํ•„์š”ํ•˜๊ณ , ์•ฝ๊ฐ„์˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๋ฉค๋ฒ„๋“ค์˜ ์†์งˆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ณธ ํ”„๋กœ์ ํŠธ์˜ ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•˜์—ฌ ์ž‘์—…์„ ํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” ์ด์ „๊นŒ์ง€ ๋ฐฉ์‹๊ณผ๋Š” ๋‹ฌ๋ฆฌ https://github.com/dev-study/vsns ๋กœ ์ ‘์†ํ•˜์‹  ํ›„ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์šฐ์ธก์ƒ๋‹จ์— ์žˆ๋Š” Fork ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์ž์‹ ์˜ ๊ณ„์ •์œผ๋กœ forking ํ•˜์‹  ํ›„์— ์ž‘์—…์„ ํ•˜์‹œ๊ณ  ๋ณ€๊ฒฝ๋‚ด์šฉ์— ๋Œ€ํ•œ ๋จธ์ง€๋ฅผ ์›ํ•  ๊ฒฝ์šฐ์—๋Š” pull request ์ž‘์—…์„ ํ†ตํ•˜์—ฌ ํ•˜์—ฌ ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

  • Forking๊ณผ Pull Request์— ๋Œ€ํ•œ ์‚ฌํ•ญ github ํ™ˆํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•˜์‹œ ๋ฐ”๋ž๋‹ˆ๋‹ค.

2013๋…„ 9์›” 01์ผ, hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ธฐ๋Šฅ์ถ”๊ฐ€

  • Community ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Community ๋ฆฌ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ–ˆ๊ณ , User์™€ Community ๋ชจ๋ธ์„ ์—ฐ๊ฒฐ์„ ๋‹ค๋Œ€๋‹ค๋กœ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ Associate๋ผ๋Š” join ๋ชจ๋ธ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

    class Community < ActiveRecord::Base
      has_many :associates, dependent: :destroy
      has_many :users, :through => :associates
      has_many :items, :through => :users
    end
    
    class Associate < ActiveRecord::Base
      belongs_to :user
      belongs_to :community
    
      before_save :default_values
    
      def default_values
        self.access_type = "member"
      end
    end
    
  • ๊ทธ๋ฆฌ๊ณ  User ๋ชจ๋ธ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ด€๊ณ„์„ค์ •์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

    in app/models/user.rb

    has_many :associates
    has_many :communities, :through => :associates
    
  • Community ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    1. Community ์ƒ์„ฑ๊ธฐ๋Šฅ : ์šฐ์ธก My Join Communities ์œ„์ ฏ์˜ ์•„๋ž˜์— ๋ณด๋ฉด Create a community ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฐ”๋กœ ์•„๋ž˜์— ์ž…๋ ฅ์ฐฝ์ด ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ์ฐฝ์— ์ปค๋ฎค๋‹ˆํ‹ฐ๋ช…์„ ์ž…๋ ฅํ•˜๊ณ  ์—”ํ„ฐํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด ajax ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ My Join Communities ๋ชฉ๋ก์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ด ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์€ ๋‘๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. :presence => true, :uniqueness => true.
    2. My Join Communities ์—๋Š” ๋ณธ์ธ์ด ๋ฉค๋ฒ„๋กœ ๋“ฑ๋ก๋œ Community๊ฐ€ ๋ณด์ด๊ฒŒ ๋˜๋Š”๋ฐ, 10๊ฐœ๊ฐ€ ๋„˜์–ด๊ฐˆ ๋•Œ๋Š” 10๊ฐœ๋งŒ ํ‘œ์‹œ๋˜๊ณ  ๊ทธ ์•„๋ž˜์— 10๊ฐœ๋ฅผ ๋บ€ ์ˆ˜๋ฅผ more... ๋งํฌ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ „์ฒด ๋ชฉ๋ก์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
    3. ๊ฐ Community ํ•ญ๋ชฉ์˜ ์˜ค๋ฅธ์ชฝ์—๋Š” ๊ฐ€์ž…(join)/ํƒˆํ‡ด(leave) ๋งํฌ๊ฐ€ ์žˆ์–ด์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ฐ€์ž… ๋ฐ ํƒˆํ‡ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
    4. My Join Communities ์— ๋ณด์ด๋Š” ๊ฐ Community ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๊ฐ€์ž…๋œ ๋ชจ๋“  ๋ฉค๋ฒ„์˜ items ๋“ค์ด ๋ณด์—ฌ์ง‘๋‹ˆ๋‹ค.
    5. ์ƒ๋‹จ ๋ฉ”๋‰ด ์ค‘ My Communities ๋Š” ๋ณธ์ธ์ธ ๊ฐœ์„คํ•œ Community ๋ชฉ๋ก์„ ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.

2013๋…„ 8์›” 30์ผ (#2), hschoi branch์—์„œ dkim branch๋ฅผ ์ƒ์„ฑํ•จ.

2013๋…„ 8์›” 30์ผ (#1), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  • ๋ณ€์šฉํ›ˆ๋‹˜์ด tagsinput-rails ์ ฌ์„ ์ด์šฉํ•˜์—ฌ ์ฝ”๋”ฉํ•ด ์ฃผ์‹  ๋ถ€๋ถ„์„ bootstrap-tagsinput-rails ์ ฌ์œผ๋กœ ๋Œ€์น˜ํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Twitter Bootstrap์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์„œ ์Šคํƒ€์ผ๋ง์ด ์–ด์šธ๋ฆฌ ์•Š๋”๊ตฐ์š”. ๊ทธ๊ฒƒ ๋ง๊ณ ๋Š” ์ž˜ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  • ๊ทธ๋ž˜์„œ ๊ฒ€์ƒ‰ํ–ˆ๋”๋‹ˆ bootstrap-tagsinput ์ด๋ผ๋Š” jQuery plugin์ด ์žˆ์–ด์„œ ์ด๊ฒƒ์„ assets pipeline์„ ์ด์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ ฌ์œผ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. https://github.com/rorlab/bootstrap-tagsinput-rails

Bootstrap::Tagsinput::Rails

Original Git source - https://github.com/timschlechter/bootstrap-tagsinput

To gemify the assets of bootstrap-tagsinput jQuery plugin for Rails >= 3.1

Compatibility

Designed for Bootstrap 2.3.2 and 3

Installation

Add this line to your application's Gemfile:

gem 'bootstrap-tagsinput-rails'

And then execute:

$ bundle

Or install it yourself as:

$ gem install bootstrap-tagsinput-rails

Usage

in app/assets/application.js

//= require bootstrap-tagsinput

in app/assets/application.css

*= require bootstrap-tagsinput

in form view, you should add data-role='tagsinput' within input tag as the follows: for example, in simple-form view template,

<%= f.input :tag_list, input_html:{data:{role:'tagsinput'}} %>

That's it

2013๋…„ 8์›” 28์ผ(#6), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  • Comment๊ฐ€ ํ•˜๋‚˜ ์ถ”๊ฐ€๋˜๋ฉด ํ•ด๋‹น Item์˜ ๋ชจ๋ธ ๊ฐ์ฒด์˜ updated_at ๋‚ ์งœ๊ฐ€ ๊ฐฑ์‹ ๋˜์–ด ํŽ˜์ด์ง€์˜ ์ตœ์ƒ๋‹จ์— ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    in app/models/comment.rb

    belongs_to :commentable, polymorphic: true, touch: true
    

    ์ด๋ฅผ ์œ„ํ•ด์„œ touch: true ์˜ต์…˜์„ ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

2013๋…„ 8์›” 28์ผ(#5), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ๊ถŒํ•œ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • Gemfile์— authority & rolify ๋‘๊ฐœ์˜ ์ ฌ ์ถ”๊ฐ€ํ•˜๊ณ  bundle install ํ•ฉ๋‹ˆ๋‹ค.

  • ์ค€๋น„ ์ž‘์—…์„ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค.

    # Create the ApplicationAuthorizer from Authority 
    $ rails generate authority:install
    
    # Create the Role class from rolify
    $ rails generate rolify:role
    
    # Create related tables
    $ rake db:migrate
    
  • ๊ถŒํ•œ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์˜ ์ž๋ฃŒ๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

  • ์ด์ œ ๋ถ€ํ„ฐ๋Š” ๋ณธ์ธ์ด ์ž‘์„ฑํ•œ ๊ธ€์ด๋‚˜ ๋Œ“๊ธ€์— ๋Œ€ํ•ด์„œ๋งŒ ๊ถŒํ•œ์ด ์ฃผ์–ด์ง‘๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ธ€์ด๋‚˜ ๋Œ“๊ธ€์€ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค

2013๋…„ 8์›” 28์ผ(#4), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ๋Œ“๊ธ€๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • Comment ๋ชจ๋ธ์˜ ์ƒ์„ฑ. ์ด ๋ชจ๋ธ๋„ polymorphic association์œผ๋กœ ์–ด๋– ํ•œ ๋ชจ๋ธ์—๋„ ๋ถ™์ผ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

     $ rails g model comment user:references commentable:references{polymorphic} body:text
     invoke  active_record
     create    db/migrate/20130827234430_create_comments.rb
     create    app/models/comment.rb
     invoke    test_unit
     create      test/models/comment_test.rb
     create      test/fixtures/comments.yml
    
     $ rake db:migrate
     ==  CreateComments: migrating =================================================
     -- create_table(:comments)
      -> 0.0101s
     ==  CreateComments: migrated (0.0101s) ========================================
    
  • [์ฃผ์˜] simple_form ์ ฌ ์„ค์น˜ํ•œ ๋‹ค์Œ์— $ rails g simple_form:install --bootstrap ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜์˜€๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. simple_form์˜ class๋ฅผ form-vertial๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์ง€๋งŒ, ์ ์šฉ์ด ๋˜์ง€ ์•Š๋Š”๊ตฐ์š”. ๊ทธ๋ž˜์„œ ๋‹ค์‹œ $ rails g simple_form:install --bootstrap ๋ช…๋ น์œผ๋กœ ๋ฅ์–ด์“ฐ๊ธฐ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ default๊ฐ€ form-vertical ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ถ”๊ฐ€ ์ž‘์—…์€ views/devise/ ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์˜ registraion๊ณผ session ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š” simple_form์˜ class๋ฅผ form-horizontal๋กœ ๋ณ€๊ฒฝํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  comment ํผ์—์„œ๋Š” ๋ณ„๋„์˜ class๋ฅผ ์ง€์ •ํ•  ํ•„์š”๊ฐ€ ์—†๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • Comment ๋ชจ๋ธ์„ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ์ปจํŠธ๋กค๋Ÿฌ์™€ ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    in app/controllers/comments_controller.rb

    class CommentsController < ApplicationController
      
      def create
        @commentable = comment_params[:commentable_type].classify.constantize.send('find',comment_params[:commentable_id])
        comment_params[:user_id] = current_user.id
        flash[:notice] = "A comment was successfully created."
        respond_to do |format|
          if @comment = @commentable.comments.create(comment_params)
            format.html { redirect_to @comment, notice: 'Comment was successfully created.' }
            format.json { render json: @comment, status: :created, location: @comment }
            format.js
          else
            format.html { render action: "new" }
            format.json
          end
        end
      end
    
      def destroy
        comment = Comment.find(params[:id])
        @commentable = comment.commentable_type.classify.constantize.send('find', comment.commentable_id)
        @comment = @commentable.comments.find(params[:id])
        @comment.destroy
        flash[:alert] = "A comment was successfully deleted."
        respond_to do |format|
          format.html { redirect_to items_url, alert: 'Comment was successfully deleted.' }
          format.json { head :ok }
          format.js
        end
      end
    
      private
    
      def comment_params
        params.require(:comment).permit(:body, :user_id, :commentable_id, :commentable_type)
      end
    end
    
  • ์—ฌ๊ธฐ์„œ๋Š” ์ •์‹ ์„ ๋˜‘๋ฐ”๋กœ ์ฐจ๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. polymorphic ๊ด€๊ณ„๋กœ comment ๊ฐ์ฒด๋“ค์„ ๋‹ค๋ฃจ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ ์ค‘์—๋Š” ์ƒ์†Œํ•œ ๊ฒƒ๋“ค์ด ๋ณด์ž…๋‹ˆ๋‹ค. classify๋‹ˆ constantize๋‹ˆ ํ•˜๋Š” ๊ฒƒ๋“ค์ด์ฃ . commentable_type์œผ๋กœ ๋„˜์–ด์˜ค๋Š” ๊ฐ’์€ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ์ € ๋ฌธ์ œ์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์‹ค์ œ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„˜๊ฒจ ๋ฐ›์€ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง€๊ณ  ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ(classify), ์ƒ์ˆ˜ํ™”(constantize)ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ํด๋ž˜์Šค ์ƒ์ˆ˜์— ๋Œ€ํ•ด์„œ send ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ finder ๋ฉ”์†Œ๋“œ๋ฅผ ์ธ์ˆ˜๋กœ ๋„˜๊ฒจ ์ฃผ๋ฉด runtime์—์„œ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง€๊ณ  ์‹ค์ œ ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์กฐ๊ธˆ ์–ด๋ ต์ฃ ? ใ…Žใ…Žใ…Ž.

  • ๋‚˜๋จธ์ง€ comment์— ๋Œ€ํ•œ ๋ทฐ ํ…œ๋ธ”๋ฆฟ์„ ๋งŒ๋“  ๊ฒƒ์€ ๋ณ„๋„์˜ ์„ค๋ช…์ด ํ•„์š”์—†์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

2013๋…„ 8์›” 28์ผ(#3), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ๊ธด๊ธ‰ ํŒจ์น˜

  • ใ…Žใ…Žใ…Ž. ๋†€๋ž˜์…จ์ฃ ? ๋‹ค๋ฆ„์ด ์•„๋‹ˆ๋ผ pageless ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ, ์ •์ž‘ ํ•„์š”ํ•œ views/items/index.js.erb ํŒŒ์ผ์ด ์—†๊ตฐ์š”. ์ถ”๊ฐ€ํ•ด์„œ ๋ฐฐํฌํ–ˆ์Šต๋‹ˆ๋‹ค.

    in views/items/index.js.erb

    $("#items").html("<%= j render(@items) %>");
    

๋กœ์ปฌ ๊ฐœ๋ฐœ๋ชจ๋“œ ์…‹ํŒ…์™„๋ฃŒ !!!

: as of 2013๋…„ 8์›” 28์ผ, 7:00am (#2)

  • ์ด ์‹œ๊ฐ„ ์ดํ›„์—๋Š” if Rails.env == 'development' ์ธ ๊ฒฝ์šฐ, ๋””ํดํŠธ ๊ฐœ๋ฐœ๋ชจ๋“œ DB๋Š” sqlite3๋กœ, carrierwave ์ €์žฅ์†Œ๋Š” ๋กœ์ปฌ ํŒŒ์ผ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

  • ๋กœ์ปฌ์—์„œ๋„ production ๋ชจ๋“œ๋ฅผ ๋Œ๋ ค ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๋•Œ๋Š” ๋‘๊ตฐ๋ฐ๋ฅผ ์ฝ”๋ฉ˜ํŠธ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    1. config/initializer/carrierwave.rb ํŒŒ์ผ ์ค‘์—์„œ 2-13 ๋ผ์ธ์„ ์ฃผ์„์ฒ˜๋ฆฌํ•ด ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    2. app/uploaders ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š” ๊ฐ ํŒŒ์ผ๋“ค์„ ์—ด์–ด์„œ(ํ˜„์žฌ 2๊ฐœ์˜ ์—…๋กœ๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค), storage :file ์œผ๋กœ ๋ณ€๊ฒฝํ•ด ์ฃผ์‹œ๊ณ  if ์กฐ๊ฑด์ ˆ์€ ์ฝ”๋ฉ˜ํ„ฐ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฉ๋‹ˆ๋‹ค.
    # Choose what kind of storage to use for this uploader:
    storage :file
    # storage :fog
    #if Rails.env == 'production'
    #  storage :aws
    #else
    #  storage :file
    #end
    
  • ๊ทธ ๋™์•ˆ ๋‹ค๋ฅธ ๋ฉค๋ฒ„๋“ค์˜ ๊ณ ์ถฉ ์ž˜ ์•Œ์ง€ ๋ชปํ•œ ์  ์ฃ„์†ก์Šค๋Ÿฝ๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋กœ์ปฌ ๊ฐœ๋ฐœํ™˜๊ฒฝ์—์„œ๋„ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์…‹ํŒ…ํ•ด์„œ ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์„ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒํ•˜๋ฉด ์ €์—๊ฒŒ ์—ฐ๋ฝ์„ ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. rorlab@gmail.com

2013๋…„ 8์›” 28์ผ (#1), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  • pageless-rails ์ ฌ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ฌ์€ will_paginate ์ ฌ์„ ์ด์šฉํ•˜์—ฌ pagination์„ ๊ตฌํ˜„ํ•œ ์ƒํƒœ์—์„œ bottom-less ๋˜๋Š” endless pagination์ด ๋˜๋„๋ก ๋„์™€ ์ฃผ๋Š” jquery plugin์ž…๋‹ˆ๋‹ค.

in Gemfile,

gem 'pageless'

์ด๋ฏธ will_paginate ์ ฌ์€ ์„ค์น˜๋˜์–ด ์žˆ์œผ๋‹ˆ ์—ฌ๊ธฐ์„œ๋Š” ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด์ œ Gemfile์„ ์ €์žฅํ›„ bundle install ํ•ฉ๋‹ˆ๋‹ค.

in app/assets/javascripts/application.js, add the following code line.

//= require jquery.pageless
  

in app/helpers/application_helper.rb

def pageless(total_pages, url=nil, container=nil)
  opts = {
      :totalPages => total_pages,
      :url        => url,
      :loaderMsg  => 'Loading more pages...',
      :loaderImage => image_path('load.gif')
  }

  container && opts[:container] ||= container

  javascript_tag("$('#items').pageless(#{opts.to_json});")
end

์œ„์™€ ๊ฐ™์ด application ํ—ฌํผ ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๋ฉด erb ์ฝ”๋”ฉ์—์„œ pageless ๋ฉ”์†Œ๋“œ๋ฅผ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  pageless pagination ์„ ์›ํ•˜๋Š” view template ํŒŒ์ผ(views/items/index.html.erb)์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

<div class="items"> 
    <%= render @items %>
</div>
<%= will_paginate @items %>
<%= pageless(@items.total_pages, items_path, '#items') %>

ํ•œํŽธ, items_controller.rb ํŒŒ์ผ์˜ index ์•ก์…˜์—์„œ๋Š” @items ๋ณ€์ˆ˜์— paginate ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ค๋‹ˆ๋‹ค.

@items = @items.order(updated_at: :desc).paginate(page: params[:page], per_page: 10)

2013๋…„ 8์›” 27์ผ, hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  • ์ ฌ ์ถ”๊ฐ€ : slimbox2-rails v2.05.2 (https://github.com/rorlab/slimbox2-rails)
  • ์ด ์ ฌ์€ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ lightbox ๋กœ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŠน์ • ํŽ˜์ด์ง€์˜ ๋งํฌ ์ค‘์— rel ์†์„ฑ์ด 'light-xxx' ์™€ ๊ฐ™์ด ๋™์ผํ•œ ๊ฒฝ์šฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” lightbox์—์„œ ์ขŒ์šฐ ํ™”์‚ดํ‘œ๋‚˜ ๋งˆ์šฐ์Šค ํด๋ฆญ์œผ๋กœ ์ด๋ฏธ์ง€ ์Šคํฌ๋กคํ•˜์—ฌ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. v2.05.2์—์„œ๋Š” ์ด๋ฏธ์ง€ ์›๋ณธ์ด ์Šคํฌ๋ฆฐ ํฌ๊ธฐ๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ ํ™”๋ฉด์˜ 0.8 ๋ฐฐ ํฌ๊ธฐ๋กœ ์ž๋™์œผ๋กœ ์ค„์—ฌ ๋ณด์—ฌ ์ฃผ์–ด ๋” ์ข‹์•„์กŒ์Šต๋‹ˆ๋‹ค.
  • [์ฃผ์˜] ๋ ˆ์ผ์Šค 4์—์„œ๋Š” vendor/assets/images ๋””๋ ‰ํ† ๋ฆฌ์— ์œ„์น˜ํ•˜๋Š” ์ด๋ฏธ์ง€ ํŒŒ์ผ๋“ค์ด precompile๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ์ ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ํ•ด๊ฒฐ์ฑ…์€ config/production.rb ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค. ์ฆ‰, precompile ํ•  ๋•Œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ํฌํ•จํ•˜๋ผ๋Š” ๋ง์ธ๊ฑฐ์ฃ .
# Precompile vendor/assets/images with Sprockets
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
  • likeable์ด๋ผ๋Š” polymorphic association์„ ์ด์šฉํ•˜์—ฌ ์ข‹์•„์š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ like.rb ๋ชจ๋ธ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•˜์˜€๊ณ  ์ด๊ฒƒ์€ ๋ชจ๋ธ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
$ rails g model Like likeable:references{polymorphic} user:references
  invoke  active_record
  create    db/migrate/20130827022256_create_likes.rb
  create    app/models/like.rb
  invoke    test_unit
  create      test/models/like_test.rb
  create      test/fixtures/likes.yml

์ด Like ๋ชจ๋ธ์€ User ๋ชจ๋ธ๊ณผ Item ๋ชจ๋ธ์„ ์—ฐ๊ฒฐํ•˜๋Š” Join ๋ชจ๋ธ๋กœ์„œ Like ๋ชจ๋ธ์€ ์–ด๋–ค ๋ชจ๋ธ(likeable:polymorphic)๊ณผ๋„ belongs_to ๋กœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

class Like < ActiveRecord::Base
  belongs_to :likeable, polymorphic: true, counter_cache: true
  belongs_to :user
end

๋˜ํ•œ items ๋ฐ์ด๋ธ”์—๋Š” likes_count:integer ํ•„๋“œ๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ counter_cache์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํ•„๋“œ๋กœ์„œ ์ •์ˆ˜ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด ์ค๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํด๋ž˜์Šค์˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

class AddLikesCountToItems < ActiveRecord::Migration
  def change
    add_column :items, :likes_count, :integer, default: 0
  end
end

User ๋ชจ๋ธ ํด๋ž˜์Šค์—๋Š” like!, dislike!, liking? ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๊ณ , users_controller.rb ์—๋Š” like, dislike ์•ก์…˜์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

in user.rb

def like!(item)
  likes.create!( likeable: item)
end

def dislike!(item)
  likes.find_by(likeable: item).destroy!
end

def liking?(item)
  if item.nil?
    false
  else
    likes.find_by(likeable: item).present?
  end
end

in users_controller.rb

def like 
  @user = User.find(params[:id])
  @item = Item.find(params[:item_id])
  @user.like! @item

  respond_to do |format|
    format.js
  end

end

def dislike
  @user = User.find(params[:id])
  @item = Item.find(params[:item_id])
  @user.dislike! @item

  respond_to do |format|
    format.js
  end
end

in routes.rb

get 'users/:id/like/:item_id' => 'users#like', as: :like_item
get 'users/:id/dislike/:item_id' => 'users#dislike', as: :dislike_item

in views/users/like.js.erb

$('#like_<%= @item.id%>').html("<%=j render('items/like_status', item: @item) %>");

in views/users/dislike.js.erb

$('#like_<%= @item.id%>').html("<%=j render('items/like_status', item: @item) %>");

Like์ƒํƒœ๋ฅผ view ํ…œํ”Œ๋ฆฟ์— ํ‘œ์‹œํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด erb ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

<%= item.likers.size %>
<%= link_to_unless( current_user.liking?(item), "Like", like_item_path(current_user.id, item.id), class: 'dislike_state', remote: true) do %>
  <%= link_to "Liked", dislike_item_path(current_user.id, item.id),  remote: true %>
<% end if user_signed_in? %>

์ƒ์„ธํ•œ ๊ฒƒ์€ ์†Œ์Šค๋ฅผ ๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

2013๋…„ 8์›” 26์ผ(#2), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

Carrierwave์ ฌ์˜ ์ €์žฅ์†Œ๋กœ aws ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ
  • ์ด๋ฅผ ์œ„ํ•œ ์ ฌ ์ถ”๊ฐ€ : carrierwave-aws (Gemfile์— ์ถ”๊ฐ€ํ•˜๊ณ  bundle install)

  • config/initializers/carrierwave.rb ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ ํ›„ ์•„๋ž˜์™€ ๊ฐ™์ด carrierwave ์„ค์ •์ถ”๊ฐ€ํ•˜๊ธฐ (ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” aws ๋ณธ์ธ๊ณ„์ •์—์„œ ๊ด€๋ จ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šด)

CarrierWave.configure do |config|
  config.storage    = :aws
  config.aws_bucket = ENV['S3_BUCKET_NAME']
  config.aws_acl    = :public_read
  config.asset_host = 'http://[bucket_name].s3-website-ap-northeast-1.amazonaws.com'
  config.aws_authenticated_url_expiration = 60 * 60 * 24 * 365

  config.aws_credentials = {
    access_key_id:     ENV['AWS_ACCESS_KEY_ID'],
    secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
  }
end

heroku์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋”ฐ๋กœ ์žˆ๊ตฐ์š”. ์ฐธ๊ณ (https://devcenter.heroku.com/articles/s3)

$ heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy

bucket name ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. bucket name ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ https://console.aws.amazon.com/s3/home ์ฐธ์กฐํ•˜์„ธ์š”. (bucket์€ ์•„๋งˆ์กด S3 ์ €์žฅ์†Œ์ž„)

$ heroku config:set S3_BUCKET_NAME=appname-assets

User account ๊ธฐ๋Šฅ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • ์‚ฌ์šฉ์ž ๊ณ„์ •์ •๋ณด๋ฅผ ๋ณ€๊ฒฝ์‹œ ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋„๋ก remove ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋ณธ์ธ์˜ ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ–ˆ๋‹ค๊ฐ€ ์‚ญ์ œํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ฒดํฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” ๋‹ค์‹œ ํŒŒ์ผ์—…๋กœ๋“œํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • [์ฃผ์˜์‚ฌํ•ญ] Devise ์ ฌ์„ Rails 4์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” strong parameters์— ๋Œ€ํ•œ ๋ถ€๋ถ„์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์ฐธ๊ณ ๋Š” https://github.com/plataformatec/devise#strong-parameters ์ž…๋‹ˆ๋‹ค.

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # Devise with strong parameters
  before_filter :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:avatar, :email, :password, :password_confirmation) }
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:avatar, :email, :password, :password_confirmation, :current_password, :remove_avatar) }
  end
end

2013๋…„ 8์›” 26์ผ(#1), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ๋ฐฐํฌ ์‹œ๋ฌผ๋ ˆ์ด์…˜ ๋ชฉ์ ์œผ๋กœ heroku์— ๋ฐฐํฌ

Heroku์— ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ž‘์—…ํ•œ ๋‚ด์šฉ์„ ์š”์•ฝํ•ด ๋‘ก๋‹ˆ๋‹ค.
  • Gemfile์— ์•„๋ž˜์˜ ์ ฌ์„ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.
group :production do
  gem 'pg'
  gem 'rails_12factor'
end

๊ทธ๋ฆฌ๊ณ , bundle install ํ•ฉ๋‹ˆ๋‹ค.

  • config/environments/production.rb ํŒŒ์ผ์„ ์—ด์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด ์ค๋‹ˆ๋‹ค.
config.serve_static_assets = true
  • ๋‹ค์Œ์œผ๋กœ๋Š” assets์„ ์‚ฌ์ „ ์ปดํŒŒ์ผ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค.
$ RAILS_ENV=production rake assets:precompile

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์—…ํ•œ ๋‚ด์šฉ์„ git ์ €์žฅ์†Œ์— commit ํ•ฉ๋‹ˆ๋‹ค

์ด์ œ๋ถ€ํ„ฐ๋Š” heroku์— ์‹ค์ œ๋กœ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.
  • cd vsns/bigpie ๋กœ ์ด๋™ํ•œ ๋‹ค์Œ์— git init ๋ช…๋ น์œผ๋กœ bigpie ๋””๋ ‰ํ† ๋ฆฌ์— ๋Œ€ํ•œ git ํ™˜๊ฒฝ์„ ์ดˆ๊ธฐํ™” ์ค๋‹ˆ๋‹ค.
vsns/bigpie $ git init
vsns/bigpie $ git add .
vsns/bigpie $ git commit -m 'initial commit for heroku deployment'
  • CLI์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ, heroku์— ์›น์„œ๋ฒ„์™€ git ์ €์žฅ์†Œ๋ฅผ ๋™์‹œ์— ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
vsns/bigpie $ heroku create
Creating vast-crag-4195... done, stack is cedar
http://vast-crag-4195.herokuapp.com/ | git@heroku.com:vast-crag-4195.git
  • ์ด์ œ heroku ๋ผ๋Š” ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋“ฑ๋กํ•ด ์ค๋‹ˆ๋‹ค.
vsns/bigpie $ git remote add heroku git@heroku.com:vast-crag-4195.git
  • ๋‹ค์Œ์œผ๋กœ heroku master ๋ธŒ๋žœ์น˜๋กœ ํ˜„์žฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋ธŒ๋žœ์น˜๋ฅผ git push ํ•ฉ๋‹ˆ๋‹ค.
vsns/bigpie $ git push heroku master

heroku๋กœ ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด migration ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค.

vsns/bigpie $ heroku run rake db:schema:dump

์ด์ œ ๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ์ž…๋ ฅ์ฐฝ์— http://vast-crag-4195.herokuapp.com/ ์„ ์ž…๋ ฅํ•˜๊ณ  ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€์˜ ์„ค์น˜๊ณผ์ •์—์„œ ๋ณ„๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋‹ค๋ฉด ์›นํŽ˜์ด์ง€๊ฐ€ ์ œ๋Œ€๋กœ ๋ณด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • My Posts ์œ„์ ฏ์„ ์˜ค๋ฅธ์ชฝ sidebar์— thumbnail ํ˜•์‹์œผ๋กœ ๋ณด์—ฌ ์ฃผ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • My Posts ์œ„์ ฏ์˜ ๊ฐ thumbnail์„ ๋งˆ์šฐ์Šค ์˜ค๋ฒ„ํ•˜๋ฉฐ box shadow๊ฐ€ ๋ณด์ด๊ณ  ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น item ์ •๋ณด๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

2013๋…„ 8์›” 25์ผ(#4), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => ๋ณธ์ธ์˜ ๊ณ„์ •์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ.

  1. item form์— ์—…๋กœ๋“œ๋œ photo ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ์ด๋ฏธ์ง€๋ฅผ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” checkbox๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์‚ญ์ œ checkbox๋ฅผ ์ฒดํฌํ•œ ํ›„ submit ํ•˜๋ฉด ์ด์ œ๋ถ€ํ„ฐ๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.
  2. item index ํŽ˜์ด์ง€์—์„œ๋„ ๊ฐ ํฌ์ŠคํŠธ๋งˆ๋‹ค tag ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด์ด๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
  3. followers์™€ followings ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋งํฌ๋ฅผ ์—ฐ๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  4. navbar์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๋ฐฐ์—ดํ–ˆ์Šต๋‹ˆ๋‹ค.
  5. ๊ทธ๋ฆฌ๊ณ  ๋กœ๊ทธ์ธ ์ƒํƒœ์—์„œ๋Š” ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ navbar์— ํ‘œ์‹œ๋˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  6. ๋˜ํ•œ ์ด๋ฉ”์ผ ๋ฉ”๋‰ด์˜ ํ•˜์œ„ ๋ฉ”๋‰ด๋ฅผ ๋‘์–ด ๋ณธ์ธ์˜ ๊ณ„์ • ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  7. will_paginate ์ ฌ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

2013๋…„ 8์›” 25์ผ(#3), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => Summernote ์œ„์ง€์œ„ํฌ ์—๋””ํ„ฐ ์ถ”๊ฐ€ํ•จ.

  1. item form์˜ description ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜๋Š” ์ฐฝ์— summernote ์œ„์ง€์œ„๊ทธ ์—๋””ํ„ฐ๋ฅผ ๋ถ™์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด summernote-rails ๋ผ๋Š” ์ ฌ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์นด์นด์˜ค์˜ ํ™์˜ํƒ๋‹˜์ด ๋งŒ๋“œ์‹  summernote ์—๋””ํ„ฐ๋ฅผ rails์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ฐ€ ๋งŒ๋“  ์ ฌ์ž…๋‹ˆ๋‹ค๋งŒ, ์‹œํ—˜์ ์œผ๋กœ ์‚ฌ์šฉํ•ด ๋ดค์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ๋กœ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.
  2. summernote-rails ์ ฌ์„ ์‚ฌ์šฉํ•˜๋‹ˆ turbolinks์™€์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ํŽ˜์ด์ง€๊ฐ€ ๋ณด์—ฌ์งˆ ๋•Œ ์—๋””ํ„ฐ๊ฐ€ ๋ณด์ด์ง€ ์•Š๊ฒŒ ๋˜์–ด juqery-turbolinks ๋ผ๋Š” ์ ฌ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด์„œ๋Š” Gemfile์— ์ฝ”๋ฉ˜ํŠธ ์ถ”๊ฐ€ํ•ด ๋†“์•˜์Šต๋‹ˆ๋‹ค.
  3. summernote-rails ์ ฌ๊ณผ์˜ ์ถฉ๋Œ ๋•Œ๋ฌธ์— flatui-rails ์ ฌ์„ ์ œ๊ฑฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  4. item form์˜ file upload๋ฅผ ์ด์ค€ํ—Œ๋‹˜์ด ๋งŒ๋“ค์–ด ๋†“์œผ์‹  ๊ฒƒ์„ ์ฐธ๊ณ ํ•˜์—ฌ simple_form_bootstrap_file_input.rb ํŒŒ์ผ์„ config/initializers ๋””๋ ‰ํ† ๋ฆฌ์— ์ถ”๊ฐ€ํ•˜์—ฌ ์ด์˜๊ฒŒ ๋ณด์ด๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
  5. item photo ์ž…๋ ฅ์„ ๋กœ์ปฌ๋จธ์‹ ์˜ ์‹œ์Šคํ…œ ํŒŒ์ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๋ฏธ์ง€ URL์„ ์ž…๋ ฅํ•ด๋„ ์—…๋กœ๋“œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์šฐํ•ด์„œ item.rb ๋ชจ๋ธ ํด๋ž˜์Šค์— attr_accessor :remote_photo_url ์„ ์ง€์ •ํ•ด ์ฃผ์—ˆ๊ตฌ์š”. items_controller.rb ํŒŒ์ผ์˜ item_params์˜ permit ์˜ต์…˜์— :remote_photo_url ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  6. ๊ทธ๋ฆฌ๊ณ  items ํ…Œ์ด๋ธ”์˜ description ํ•„๋“œ์˜ ๋ฐ์ดํ„ฐ ์†์„ฑ์„ string ์—์„œ text ๋กœ ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  7. items ๋ณด์—ฌ์ง€๋Š” ์ˆœ์„œ๋ฅผ updated_at ๋‚ ์งœ๋ฅผ DESC๋กœ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ตœ๊ทผ ๊ฐฑ์‹ ๊ธ€์ด ๊ฐ€์žฅ ์œ„๋กœ ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2013๋…„ 8์›” 25์ผ(#2), bbugguj ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ => Tagging ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • gem 'acts-as-taggable-on'์„ ์‚ฌ์šฉํ•˜์—ฌ Tagging ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • Item model์— tagging ๊ด€๋ จ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (acts_as_taggable)
  • Item ์ž…๋ ฅ form์—์„œ tag list ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •
  • Item show.html์— tag ๋ณด์—ฌ์ฃผ๋„๋ก ์ˆ˜์ •. tag์— /tags/:tag ๋งํฌ ์ถ”๊ฐ€
  • /tags/:tag ๋ผ์šฐํŠธ ์ถ”๊ฐ€
  • ItemsController์˜ index์— tag๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • .gitignore ํŒŒ์ผ์— big_pie/public/uploads/* ์ถ”๊ฐ€

2013๋…„ 8์›” 25์ผ(#1), hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  1. items ์ปจํŠธ๋กค๋Ÿฌ์˜ index์™€ show ์•ก์…˜ ๋ทฐ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์„ ๋ฆฌํŒฉํ† ๋งํ•˜์˜€์Šต๋‹ˆ๋‹ค. index view ์—์„œ๋Š” _item.html.erb ์ด๋ผ๋Š” partial template ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๊ฐ item ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ ์ฃผ๋Š” ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ์ถ”์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ index.html.erb ํŒŒ์ผ์—๋Š” <%= render @items %> ์ด ํ•œ์ค„๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ „์ฒด item ํฌ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  2. show action view ์—์„œ๋Š” _show_item.html.erb ์ด๋ผ๋Š” partial template ํŒŒ์ผ์„ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ํ•˜๋‚˜์˜ item ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ๊ธˆ ์ด์˜๊ฒŒ ๋ณด์ด๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ „์ฒด์ ์œผ๋กœ๋Š” responsive design์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ง์ด์ฃ . ๋”ฐ๋ผ์„œ show action view template ํŒŒ์ผ์—๋Š” <%= render 'show_item', item: @item %>์™€ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฆฌํŒฉํ† ๋ง๋˜๋Š” ๊ฒƒ์ด์ฃ .
  3. _item_html.erb partial template ํŒŒ์ผ์—์„œ ์ถ”๊ฐ€ํ•œ ๊ธฐ๋Šฅ์€ actions๋ผ๋Š” div ํƒœ๊ทธ๋‚ด์— ์„ธ๊ฐ€์ง€ action ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค: Show, Edit, Destroy. ์ด actions div ํƒœ๊ทธ๋Š” ๋””ํดํŠธ ์ƒํƒœ์—์„œ๋Š” display:none ์œผ๋กœ ๋˜์–ด ์žˆ์ง€๋งŒ, div.hover ์‹œ์— display:inline์œผ๋กœ ๋ณด์ด๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋งˆ์šฐ์Šค๋ฅผ ํ•˜๋‚˜์˜ post์— ๊ฐ€์ ธ๊ฐ€๋ฉด post ์ขŒ์ธกํ•˜๋‹จ์— ์„ธ๊ฐœ์˜ ์•ก์…˜ ๋ฒ„ํŠผ๋“ค์ด ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2013๋…„ 8์›” 24์ผ, hschoi ๋ธŒ๋žœ์น˜์— ์ถ”๊ฐ€๋œ ๋‚ด์šฉ

  1. ์ „์ฒด ๋ ˆ์ด์•„์›ƒ์„ ๊ฐ€๋กœ 2๋‹จ์œผ๋กœ ๊ตฌ์„ฑํ•˜์˜€๊ณ , ์•ฝ๊ฐ„์˜ ๋ฆฌํŒฉํ† ๋ง์„ ์ˆ˜ํ–‰ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  2. file upload์‹œ ํ•œ๊ธ€ํŒŒ์ผ๋ช…์ผ ๊ฒฝ์šฐ ํ•œ๊ธ€์ด ๋ฐ‘์ค„๋กœ ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์„ ํ•œ๊ธ€์ด ์ œ๋Œ€๋กœ ํ‘œ์‹œ๋˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. (config/initializers/carrierwave.rb ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.)
  3. devise ์ ฌ์˜ devise:views ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ app/views/devise/ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋ทฐํ…œํ”Œ๋ฆฟ ํŒŒ์ผ๋“ค์„ ๊ฐ€์ง€๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  4. ๊ทธ๋ฆฌ๊ณ  follow ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ users_controller.rb ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” followings, followers, follow, unfollow ์•ก์…˜์„ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.
  5. User ๋ชจ๋ธ์—๋Š” avatar ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์„œ ๊ฐœ์ธ ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ์˜ฌ๋ฆฌ ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์ง„์ด ์—†๋Š” ๊ฒฝ์šฐ ๋””ํดํŠธ ์ด๋ฏธ์ง€(profile_default.png)๊ฐ€ ๋ณด์ด๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Relationship ์ด๋ผ๋Š” ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด User ๋ชจ๋ธ๊ณผ์˜ ๊ด€๊ณ„์„ค์ •์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, User ๋ชจ๋ธ์—๋Š” following?, follow!, unfollow! ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.
  6. relationships_controller.rb ํŒŒ์ผ์€ ํ˜„์žฌ๋กœ์„œ๋Š” ๋”ฑํžˆ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

About

Dev.Study - Official VSNS Repository since 2013.9.1

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 63.0%
  • JavaScript 26.6%
  • CSS 9.0%
  • CoffeeScript 1.4%