Languages/Ruby or Rails2008.08.01 13:36

이 문제는 나그네 님께서 지적해주신 문제입니다. 최신 버전의 Rails는 일반 html 파일에 포함된 form의 input 필드들과 연동할때, 약간의 문제가 있습니다.

가령 Beginning Ruby on rails의 5장에 수록된 예제처럼 input.html 파일을 다음과 같이 만들었다고 해 봅시다.

<html>
<body>
    <form action="/look/at">
    <input type="text" name="text1"/>
    <input type="submit"/>
    </form>
</body>
</html>

이 form에 뭔가를 입력하고 submit 버튼을 누르면 /look/at 액션이 실행될 것이고, 그 결과가 화면에 출력될 것입니다. 그런데 그냥 이렇게만 하면 별 문제가 없다가, 위의 html 코드를 다음과 같이 바꾸면 문제가 발생합니다.

<html>
<body>
    <form action="/look/at" method="post">
    <input type="text" name="text1"/>
    <input type="submit"/>
    </form>
</body>
</html>

위와 같이 바꿔놓고 submit  버튼을 눌러보면, 다음과 같은 오류가 발생하는 것을 볼 수 있습니다.

ActionController::InvalidAuthenticityToken in LookController#at

액션 컨트롤러 쪽에서 AuthenticityToken이라는 것을 요구하는데 그게 없기 때문에 발생하는 오류입니다. 이 문제를 좀 더 정확하게 이해하기 위해, 다음과 같이 해 봅시다. 일단 controller Look에 input이라는 액션을 추가합니다.

class LookController < ApplicationController
    def at
        @data = params[:text1]
    end

    def input
    end

end

그런 다음 위의 html 코드를 다음과 같이 바꾸고, app/views/look 아래에 input.html.erb 라는 이름으로 복사해 넣습니다.

<html>
<body>
    <% form_tag '/look/at', :method=>:post do %>
    <input type="text" name="text1"/>
    <input type="submit"/>
    <% end %>
</body>
</html>

그런 다음에, 브라우저로 /look/input을 엽니다. 그리고 나서 브라우저의 소스 코드 보기 기능을 통해 소스 코드를 봅시다. 다음과 같이 되어 있는 것을 볼 수 있습니다.

<html>
<body>
 <form action="/look/at" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="8f846ee3232eda791b4bf4c9d6d0a20478afcf8a" /></div>
 <input type="text" name="text1"/>
 <input type="submit"/>
 </form>
</body>
</html>

결국, /look/at은 method가 post일때 위의 token이 오기를 기대하는데 안오니까 불평을 해 댔던 것이죠. 이 문제를 해결하는 방법은 두가지가 있는데, 위에서처럼 모든 form 태그를 전부 form_tag 메소드를 써서 생성하는 것입니다. 그러면 알아서 넣어주니까 괜찮죠.

하지만 <div> 태그가 원래 원칙적으로 line break를 유발하는 습성이 있기 때문에, 웹 디자이너에게는 솔직히 짜증나는 부분이 될 수 있습니다. 그냥 hidden input filed로 두면 되었을텐데 div는 뭐하러 두었는지 참 ㅋㅋ

가장 간단한 해결책은 CSRF(Cross-Site Request Forgery) 공격을 막기 위해 도입된 위 feature를 강제로 동작하지 않도록 만드는 것입니다.

위의 경우라면, 컨트롤러 Look에 다음의 한줄을 넣어주세요.

skip_before_filter :verify_authenticity_token

제가 Beginning Ruby on Rails를 번역하면서 원저자가 책을 썼던 시점에 비해 바뀐 부분을 반영해 넣느라 고민을 좀 했었는데, 이렇게 책을 내놓고 보니 또 그 와중에 뭔가 새로운 기능이 계속 추가가 되어서 -_-;;

어쨌던 불편을 끼쳐드려서 죄송합니다. 앞으로도 이런 부분을 발견할 때 마다, 그리고 독자 분들의 질문이 있을 때 마다 가능한한 열심히 답변을 드리도록 하겠습니다.


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 전 원인도 모르고 그냥 첫번째 방법 썼는데 ^^ 좋은 정보 감사합니다~

    2008.08.01 14:26 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Ruby or Rails2008.07.29 09:06
Openid를 사용한 로그인 기능을 Rails를 사용하여 구현하면 굉장히 간단히 구현가능한 것으로 알려져 있습니다. http://www.aproxacs.com/122 를 보면 잘 알수 있는데요, 그런데 시키는대로 따라하다보면 뭔가 이상한 문제들이 한두가지 생기는 것을 발견할 수 있습니다.

Web Password 팝업 창이 뜬다

http://www.aproxacs.com/122 이 글에 나온 대로 구현을 하다 보면, application controller (application.rb) 를 변경해서 login_required를 before_filter로 적용하는 부분을 볼 수 있습니다. 그 의미인 즉슨 login이 안된 상태에서 action을 실행하려고 하면 (sessions 컨트롤러의 메소드들은 제외) 전부 login 창으로 redirection 되도록 만들기 위함인데, 문제는 IE 상에서 가끔 sessions 컨트롤러의 액션이 아닌 다른 액션에 접근하려고 해 보면, Openid로그인창으로 redirection이 되는게 아니라, Web Password 팝업 창이 떠버린다는 점입니다.

이 문제는 lib/ 디렉터리 아래에 있는 authenticated_system.rb 파일에 정의되어 있는 다음 메소드 때문에 발생합니다.

    def access_denied
      respond_to do |format|
        format.html do
          store_location
          redirect_to new_session_path
        end
# bjlee:
# block following 3 lines to remove annoying 'Web Password' Popup
# is displayed on the screen especially for IE.
#
#        format.any do
#          request_http_basic_authentication 'Web Password'
#        end

      end
    end

이 문제를 가장 '간단하게' 해결하려면, 위에서 보는 것 처럼 format.any do 부터 end까지를 comment 처리해주면 됩니다. (물론, 그다지 바람직한 해결책이라고는 볼 수 없습니다만...)

로그인 후에 로그인 전에 마지막으로 방문했던 페이지로 돌아가지 못한다

보통 사람들이 기대하는 것이, 로그인이 되고 나면 그 전에 마지막으로 보고 있었던 페이지로 돌아가는 것일텐데요. http://www.aproxacs.com/122 에 나온대로 해 두고 따라해 보면 그 이전 페이지로 돌아가려다가 메소드가 없다느니 객체가 nil이라느니 하는 등등의 오류 메시지가 뜰 때가 있습니다.

그것은 app/controllers/sessions_controller.rb 파일에 있는 successful_login 메소드에 포함된 오류 때문입니다. 다음과 같이 수정하면 해결됩니다.

    def successful_login
        if params[:remember_me] == "1"
            self.current_user.remember_me
            cookies[:auth_token] = {
                :value => self.current_user.remember_token ,
                :expires => self.current_user.remember_token_expires_at
            }
        end
        if ( session[:return_to] != nil )
            redirect_to session[:return_to]
        else
            redirect_to( '/' )
        end
    end

적색으로 표시한 부분이 수정한 부분입니다.



신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Languages/Ruby or Rails2008.07.17 14:47

passenger를 설치하는 절차는 우선 다음의 명령을 입력하는 것으로 시작된다.

sudo gem install passenger

엔간하면 이 절차는 정상적으로 완료될 것. 하지만 그 다음이 문제. 설치 문서에는 passenger-install-apache2-module 을 실행하라고 나오는데, 이 파일은 /var/lib/gems/1.8/gems/passenger-2.0.2/bin 디렉터리 아래에 있는데다, 결정적으로 실행 권한이 설정되어 있지 않다.

그러므로 실행하려면 그 디렉터리 아래에 가서, sudo ruby passenger-install-apache2-module 처럼 실행해 주어야 한다. 그런데 그렇게 실행해 보면, rake가 gems 디렉터리 아래에 분명 설치되어 있는데도 설치되어 있지 않다고 불평하는 일이 발생한다. (이런...)

이런 일이 발생했다면, 여러분의 gems installation에 뭔가 문제가 발생한 것이다. -_-;
http://agileweb.wordpress.com/2008/07/18/how-to-install-rails-21-on-ubuntu-in-5-steps/
위의 링크를 참조해서 여러분의 gems installation 자체를 업데이트해보는 것이 좋겠다. 그런 다음 rails, passenger 등등을 다시 설치해야 한다.

이것은 rake 실행파일이 /usr/bin/ 아래에 복사되어 있지 않기 때문에 발생하는 문제. 따라서 sudo cp /var/lib/gems/1.8/gems/rake-0.8.1/bin/rake /usr/bin 과 같이 해주어야 한다. 그러면 문제가 해결된다. (카피가 찜찜한 분은 심볼릭 링크를 걸어주는 편이 낫겠다.) 실행권한도 빠져있으니 sudo chmod +x로 걸어주어야 한다.

이렇게 하고 나서 다시 sudo passenger-install-apache2-module 를 해 보면 뭔가 make 한다는 메시지가 쫙 나오고 나서 다음과 같은 텍스트가 화면에 출력된다.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /var/lib/gems/1.8/gems/passenger-2.0.2/ext/apache2/mod_passenger.so
   PassengerRoot /var/lib/gems/1.8/gems/passenger-2.0.2
   PassengerRuby /usr/bin/ruby1.8

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

Press ENTER to continue.

/etc/apache2/conf.d 디렉터리 아래에 passenger라는 파일을 만들어 위의 설정을 그대로 입력해 보자. 그런 다음에 enter 키를 누르면 다음의 텍스트가 화면에 출력된다.

Deploying a Ruby on Rails application: an example

Suppose you have a Ruby on Rails application in /somewhere. Add a virtual host
to your Apache configuration file, and set its DocumentRoot to
/somewhere/public, like this:

   <VirtualHost *:80>
      ServerName
www.yourhost.com
      DocumentRoot /somewhere/public
   </VirtualHost>

And that's it! You may also want to check the Users Guide for security and
optimization tips and other useful information:

  /var/lib/gems/1.8/gems/passenger-2.0.2/doc/Users guide.html

Enjoy Phusion Passenger, a product of Phusion (www.phusion.nl) :-)
http://www.modrails.com/

Phusion Passenger is a trademark of Hongli Lai & Ninh Bui.

일단 여기까지 해서 설치는 끝났다. 이제 남은 일은 VirtualHost 설정을 적절히 해서 Rails의 실행 결과가 브라우저에 전송될 수 있도록 하는 것 뿐...

우선, apache에 또다른 VIrtualHost 설정을 꾸며서, 접속 도메인 명이 달라질 경우 해당 VirualHost가 실행될 수 있도록 한다.

<VirtualHost *>
    ServerAdmin byungjoon.lee@gmail.com
    ServerName www.xxxxx.com
    DocumentRoot /home/bjlee/work/rails/xxxxx/public
    RailsBaseURI /
</VirtualHost>

대략 위와 같이 하면 된다. 다만 한가지 주의할 것은, 위의 /home/.../public 디렉터리에 www-data (apache2가 실행되는 사용자명) group에 대한 읽기쓰기 권한을 주어야 한다는 것. 필자는 /home/.../work/rails 디렉터리에 가서 그 아래에 있는 모든 subdirectory에 대해 chown -R bjlee:www-data *를 실행하고, chmod -R g+w * 를 실행해 주었다.

이렇게 하고 나서 브라우저의 주소창에 www.xxxxx.com을 입력하고 접속해보면 접속이 된다. 접속이 안될 경우 해당 도메인 명이 등록이 안된 것이니 ㅋㅋ 윈도우의 hosts 파일을 고쳐서 등록된 것처럼 꾸며야 할 것.

그런데 이렇게 하면서 몇가지 프로그래머가 반드시 알아야 할 사항이 드러났는데.

1. development 모드에서는 *.rhtml의 확장자를 사용해 view template을 꾸밀 수 있었는데, production mode를 가정하는 passenger의 특성상 *.html.erb의 확장자가 아니면 인식을 못한다는 것. (Rails 2.0부터는 *.rhtml의 확장자는 더이상 사용하지 않으며, *.html.erb의 확장자를 사용해야 한다. 다만 현재로서는 하위호환성을 위해 *.rhtml을 Development 모드에서는 지원하고 있다.)

2. 원래 그런 건지 아니면 설정을 잘못해서 그런건진 몰라도 (아마 전자일듯) passenger를 사용해 rails 프로그램을 띄우면 소스코드를 바꿔도 그 결과가 바로 반영되어 실행되지는 않는다. (소스코드의 변경을 반영하려면 웹 서버를 다시 띄워야 한다.) 아마 production mode 로 release를 하는 것을 가정하는 passenger의 특성상 그러할 것. 물론 시간이 지나 모든 세션이 종료되고 난 뒤에는 수정된 코드가 다시 반영된다. :-) Rails app 디렉터리 아래에 tmp/restart.txt 파일을 'touch' 해도 된다. 이 경우에는 웹 서버 전체가 재시작되는 것이 이니라, 해당 app만 재시작된다.

여기까지만 주의하면 passenger를 통해 rails 프로그램을 쾌적하게 배포할 수 있을 것이다.

다른 문제에 대해서는 passenger를 배포하고 있는 웹 사이트에 가서 http://www.modrails.com/ 사용자 가이드를 보면 될 것이다.


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^