BLOG main image
분류 전체보기 (239)
Rails (65)
Ruby (34)
이야기 (40)
스토리큐 (61)
그 밖에.. (30)
C# (6)
드리밍 인 코드
The note of Legendre
작은아이의 생각
agiletalk's me2DAY
[rails] Growl4Rails
美소년 ㅇㅅㅇ씨의 一日
마사키군의 생각
ayukawa's me2DAY
작은아이의 생각
agiletalk's me2DAY
63,413 Visitors up to today!
Today 18 hit, Yesterday 22 hit

 SUBSCRIBE

'Flash'에 해당되는 글 2건
2009/06/16 08:29

어떤 정보가 저장되었을 때, 혹은 저장에 실패했을 때, 사용자에게 성공/실패 메시지를 보여주기 위해 사용하는 한 가지 방법은 flash message이다. controller에서 다음과 같은 식으로 flash message를 저장한다.

  1. flash[:notice] = “Logged in successfully!”

그리고 view에서 flash message를 다음과 같이 사용할 수 있다.

  1. <%= flash[:notice] %>

flash 메시지는 cookie에 저장되어 다음 요청까지 남아 있기 때문에 redirect 요청을 사용할 때 특히 유용하다.

이와 같이 flash message는 주로 공지(notice)나 에러(error) 같은 메시지를 위해 사용된다. 이런 메시지들은 전 페이지에 걸쳐 발생한다. 이들을 각 view에서 보여주는 것은 번거로울 뿐만 아니라 view마다 보여지는 방식이 다르다면 사이트를 산만하게 보이게 할 수도 있다.  일관된 방식으로 보여주는 것은 개발에도 편리하고 일관성도 유지할 수 있다. 예를 들어 ‘항상 오른쪽 상단에 공지 메시지가 보여지게 된다’ 와 같은 정책을 갖는 것이다. 이는 다음과 같이 layout에서 flash message를 보여주는 방법으로 간단히 구현할 수 있다.

  1. # layout
  2. <div id=’contents’>
  3.   <%= flash_messages %>
  4.   <%= yield  %>
  5. </div>
  6. # application_helper
  7. def flash_messages
  8.   if(flash[:notice])
  9.     content_tag(:div, flash[:notice], :class=>”notice”)
  10.   end
  11. end

이 방법은 편하기는 하지만 멋지지는 않다. jGrowl을 사용해서 좀 더 멋지게 보여지도록 하자.

jGrowl은 MAC의 growl 알림 시스템에 영감을 받은 jquery 플러그인이다. 메시지가 발생하면 투명한 메시지 박스가 보여진다. 세련된 느낌의 그 박스를 보고 있자면 기분이 좋다. 여기 데모가 있다.

jGrowl의 사용은 간단하다. jGrowl을 다운 받아서 설치(jquery.js, jquery.jgrowl.js, jquery.jgrowl.css 파일을 추가)한 후 다음과 같이 사용할 수 있다.

  1. $.jGrowl("hello jGrowl");

이제 아래와 같이 flash message들을 jGrwol을 통해 보여지도록 하자.

1

application_helper의 flash_message를 수정해서 jGrowl을 통해 메시지를 보여지도록 한다.

  1. module ApplicationHelper
      def flash_messages
        messages = []
        %w(notice error).each do |type|
          if flash[type.to_sym]
            messages << """
      $('#flash_container').jGrowl('#{flash[type.to_sym]}',
      {
        header: '#{type.upcase}',
        theme: '#{type.downcase}'
      });
            """
          end
        end
        javascript_tag """
    $(function(){
      #{messages.join}
    });
        """
      end
  2. end

flash_container 밑에 jGrowl 메시지들이 들어가도록 했다. header는 메시지의 처음에 나오는 제목이다. theme를 지정하면 메시지 element의 CSS class가 theme로 설정된다.
이제 flash_container를 layout 파일의 적당한 위치에 넣자.

  1. <div id="content">
  2.   <div id="flash_container"></div>
  3.   <%= flash_messages %>
  4.   <%= yield  %>
  5. </div>

그리고 css를 다음과 같이 주어 오른쪽 상단에 메시지들이 보여지도록 하자.

  1. div#content {
      position: relative;
    }
    div#flash_container {
      position: absolute;
      right: 5px;
    }

error 와 notice의 CSS를 설정해서 조금 더 보기 좋게 할 수도 있다.

  1. div.jGrowl-notification.error div.header {
      background: transparent url(/images/icon_error.png) no-repeat left;
      padding-left: 20px;
      color:red;
    }
    div.jGrowl-notification.notice div.header {
      background: transparent url(/images/icon_info.png) no-repeat left;
      padding-left: 20px;
      color:#009BC7;
    }
2008/06/30 16:54

SWF upload 플래시는 cookie의 값을 서버로 제대로 전송해 주지 못한다. 무슨 내용인지 궁금하면 다음을 읽어보라.

http://swfupload.org/forum/generaldiscussion/383

IE가 아닌 다른 브라우저에서는 IE의 쿠키값을 보낸다는 듯 하다.

이유야 어찌됬든 파일 업로드는 사용자가 로그인한 상태에서 행해지는 것이 대부분일테고, 그리고 사용자의 로그인을 restful authentication의 login_required 같은 before_filter에 의해 보장받고 싶다면, SWFUpload를 이용한 업로드는 문제가 있다.

세션 정보가 제대로 전해지지 않기에 login_required는 실패를 할 테고, 업로드 액션에 도달하지도 못하고 끝이 날 것이다.

 

이를 해결하는 방법 중 하나는 session 정보를 업로드 요청의 파라미터로 보내서 그것으로부터 session 정보를 복구해내는 것이다. Upload files with SWFUpload 를 보면 session 정보를 URI의 query_string에 전하고, class CGI::Session 과 class CGI::Session::CookieStore 를 해킹해서 해결했다. 이 방법은 잘 동작한다. 이렇게 해도 별 무리가 없을 듯하지만...

어떤 이유 (- 모든 요청에 대해 query_string을 조사하는 것이 꺼림직하다. -) 에서든지 session 정보를 query_string이 아닌 POST 파라미터로 보내고 싶다면 다음과 같은 방법을 사용할 수도 있다.

 

여기서는 sesion 정보를 POST 파라미터로 전하고 action의 before_filter를 이용해서 session 정보를 복구하도록 하는 방법을 소개한다.

 

1. flash의 upload 요청에 session 값을 POST 파라미터로 전해준다.

다음과 같이 swfupload가 post_parameter 에 session_id를 전해주도록 한다.

  1. new SWFUpload({
  2. post_params: {"_app_session_id" : <%= session.session_id %>},
  3. ...

% Rails 2.1에서는 session_id 에 '\n' 이 포함되어 있다. 왜 그런거지..? 그래서 javascript 에러가 발생한다. session.session_id.gsub("\n", "\\n") 이렇게 해주니까 잘 되더라.(이.. 깊이없는 땜빵....음냐..)

 

2. before_filter를 이용해서 파라미터에서 session 정보를 얻도록 한다.

SWFUpload를 이용해서 업로드를 수행하고자 하는 action을 retrieve_session_from_param 로 보호하도록 한다. retrieve_session_from_param은 params로 부터 session을 복구할 것이다. 주의할 것은 retrieve_session_from_param 가 login_require 보다 먼저 실행되어야 한다.

  1. class PhotosController < ApplicationController
  2.   before_filter :retrieve_session_from_param, :only=>[:create]
  3.   before_filter :login_required

 

2.1. retrieve_session_from_param

parameter로 부터 session 정보를 얻어오는 함수 retrieve_session_from_param을 app/controllers/application.rb에 추가한다.

  1. def retrieve_session_from_param
      session_key = ActionController::Base.session[0][:session_key]
      return if params[session_key].blank?

      self.session = CGI::Session.new(request,
        'database_manager' => CGI::Session.const_get((:cookie_store).to_s.camelize),
        'new_session' => false,
        'session_key' => session_key,
        'secret' => ActionController::Base.session[0][:secret],
        'session_data' => params[session_key],
        'session_id' => params[session_key] )   
    end

code 설명

sesson_key 가 params에 있으면 params[:session_key]로부터 session을 만들도록 하자. session_key는 environment에서 config.action_controller.session 에 적어준 그 값이다.

params[:session_key] 있다면 그로부터 session을 생성해서 controller의 session값과 바꿔치기하자. 이 때 database_manager는 CookieStore를 이용한다. 그리고 session_data라는 파라미터도 전해주는데, 이 값은 CookieStore 인스턴스를 만들때 그대로 전해질 것이다.

 

2.2. CGI::Session::CookieStore 의 해킹
CGI::Session::CookieStore가 session 정보를 session_data 에서 우선적으로 읽어올 수 있도록 하자.

config/initializers/swf_upload.rb를 만들어 다음 내용을 추가한다.(좋지 않아 보인다..)

  1. class CGI::Session::CookieStore
      alias original_initialize initialize
  2.   alias original_read_cookie read_cookie
      def initialize(session, options = {})
        @session_data = options['session_data']
        original_initialize(session, options)
      end

      def read_cookie
        @session_data || original_read_cookie
      end
    end

code의 설명

 

options['session_data'] 를 파라미터로 받으면 이 값을 @session_data 에 저장하고 있다가 read_cookie 시에 return하도록 한다. 그러면 session을 cookie에서가 아닌 입력받은 파라미터(options['session_data'])에서 얻을 수 있다.

 

 

이 글은 스프링노트에서 작성되었습니다.

prev"" #1 next