Dragonkun in Tistory

POST : 일상

블로그 옮깁니다.

또 병이 도졌습니다. -_-
이글루스, PHP로 직접 만든 블로그, 태터, 티스토리에 이어서..
이번엔 레일스로 직접 만든 블로그로 옮깁니다.

나름 마틴 파을러의 블리키를 보다가, 위키 + 블로그 형식으로 만들어보자고 만들어 봤는데..
결국은 리비젼 관리가 되는 블로그가 되어버렸습니다. -_-

딱히 여기 글을 옮기거나 이 블로그를 닫을 생각은 없지만, 더 이상 글은 이곳에 쓰지 않을 예정입니다.
(혹시 또 맘 바뀌면 어떻게 될지는 장담은 못합니다.)

아, 새 주소는 아래와 같습니다.

Dragonkun's lifestream : http://dragonkun.pe.kr
Dragonkun's Bliki : http://bliki.dragonkun.pe.kr
top

posted at

2009/01/02 01:18


POST : 프로그래밍/개발

Rails 2.1.x. 어라, 시간이 안 맞네?

간만에 손 댄 레일스
오래간만에 Rails 를 이용해서 웹 프로그램을 만들어 보고 있습니다.
간만에 뭔가 작업을 하려하니 좀 생소한 느낌도 들고...
무려 레일스는 2.1 대로 올라가 있더군요.

간단한 모델을 설계하고 scaffold 하나 생성해서 돌려 봤습니다.
그런데, 이상하게 created_at 의 시간이 9시간이나 늦는 것을 발견했습니다.

'하하. 이런.. 서버 타임존을 제대로 설정 안해뒀나 보군..'

어라, 서버 설정은 제대로 되어 있는데?

ActiveSupport::TimeWithZone
to_s(:db) 메소드를 이용하여 화면에 출력하니..
mysql 에 접속해 살펴보니 DB에 역시 9시간전인 UTC 시간이 저장되어 있더군요..

뭔가 이상한 기분이 들어서 script/console 을 열어봤습니다.
그리고선 created_at.class 를 찍어보니 이전까지는 Time 이라고 찍혀야 할 것이 ActiveSupport::TimeWithZone 이라고 찍히는군요.

오호라, Rails 2.1 에서는 타임존을 지정할 수가 있게 되었습니다.
안 그래도 이전에 Rails 의 시간이 Timestamp 가 아닌 바람에 고생을 한 기억이 있는데,
이제는 그럴 일이 없어지겠군요.

rake time:zones:local

명령으로 현재 local 시간에 해당하는 타임존을 얻을 수 있습니다.
친절하게도 'Seoul' 이라는 목록을 찾을 수 있네요.

다음은 config/environment.rb 에  다음과 같이 수정해 줍니다.

config.time_zone = 'Seoul'

아니면 더 간단하게 프로그램 내에서 아래와 같이 해도 되는 듯 합니다.

Time.zone = 'Seoul"

그리고 뷰에서는 아래처럼..

@post.created_at.localtime

혹은

@post.created_at.getlocal

후우, 잘 나오는군요. 뭐 쓸일은 거의 없겠지만 타임존을 지원하니 각각의 다른 타임존끼리의 시간 변환이나 비교 등이 쉬워지겠네요.
예전에 미투데이의 개발자 분들이 해외에서 미투질하시는 분들이 제대로 된 시간으로 이용할 수 없었다는 이야기를 얼핏 들은 적도 있는 것 같은데..
루비 1.9에서는 로컬라이징 기능이 강화된다고 하는 데에 있어서..
레일스 팀은 한 발짝 먼저 대비하고 있는 느낌이군요.  그들의 부지런함이 부럽습니다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

posted at

2008/10/16 21:27


POST : 일상

눈먼 자들의 도시

(스포일러가 있을 수 있습니다.)

눈먼 자들의 도시를 읽었습니다. 
우연히 자주 가던 커뮤니티에서 눈뜬 자들의 도시의 독후감을 읽고 한 번 보고 싶다는 생각에 우선은 전편 격인 눈먼 자들의 도시를 지난 주에 서점에서 사 왔었지요.

책의 내용은 전혀 알지 못하고 구입한 책이었습니다.  책을 펼치기 전까지는 권력에 눈먼 사람이라던가, 돈에 눈먼 사람, 사랑에 눈먼 사람들등의 이야기를 다룬 것은 아닐까 하는 생각을 가지고 있었는데, 이런.. 정말로 사람들이 그냥 아무 이유없이 갑자기 눈이 멀어버리는 이야기였습니다. 처음으로 눈먼 사람의 이야기가 나왔을 때까지만 해도 무슨 비유인지 알았는데, 점점 더 많은 사람이 눈이 멀게 되자, 그제서야 '아 이거 정말로 실명에 관한 이야기이구나'라고 생각했습니다.

아, 물론 눈이 멀었다고 하는 것이 비유적인 표현이 아니라 실명을 뜻한다는 것이지, 우리 현실의 다른 무언가를 비유하지 않는다고 하는 것은 아닙니다.  소설은 원래 모두 현실을 반영하는 비유로 이루어진 것들이니까요. 

어쨌든, 책 이야기를 하자면 정말 제가 지금 이 시점에 이 책을 읽게된 것이 참으로 기이하지 않을 수가 없네요.  언제나 익숙하기만 해서 미처 그 소중함을 몰랐던 것들..
눈이 멀어버린 상황에서도 그 환경에 하나 둘씩 적응해가며 나름의 규칙을 정해가며 살아가는 모습에서는 역시 인간이란 생명력 강한 존재라는 것을 다시금 확인할 수 있었습니다.

허나 권력들(눈이 멀지 않은 군인들 혹은 무장을 한 눈먼 자들)이 다른 사람들을 지배하고, 사람들은 인간성을 잃어가고 짐승과 다를 바 없는 삶이 되어 버린 도시의 모습들은 차마 책장을 넘기기가 힘들만큼 잔인하고도 폭력적이었지요.  하지만 그 눈먼 자들의 도시의 모습이 현실과 크게 다르지 않다는 것을 느끼는 데는 그렇게 오래 걸리지는 않더군요.

주제 사마라구는 자신의 작품 중 '예수의 제 2복음'이란 작품으로 예수의 일생을 한 명의 인간적인 차원에서 접근하여 문학화 시켰다가 교황청의 제재를 받고, 공산당 활동에 참가하기도 해서 결국은 모국에서 추방당하기까지 합니다.  그런 그는 권력에 대해서 어떻게 느꼈을까요.  작품 마지막에 나오는 의사 아내의 대화 중에 언급되는 '볼 수 있지만 보려 하지 않는 눈먼 사람들'은 마치 이 시대를 살아가는 우리에게 일침을 날리는 듯한 느낌마저 들어 책장을 덮고도 한동안 멍하니 있을 수 밖에 없었습니다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

tags

눈먼 자들의 도시, 독서, 독후감, 소설, 주제 사마라구

posted at

2008/08/24 21:35


POST : 프로젝트

공개 SW 공모대전에 참가합니다.

http://kldp.org/files/(080731)2008%EA%B3%B5%EA%B0%9CSW%EA%B3%B5%EB%AA%A8%EB%8C%80%EC%A0%84_%EC%B5%9C%EC%A2%85.jpg
공개 SW 공모대전에 참가합니다.

별 일이 없으면 공개 SW 챌린지 Linux System Monitoring Tool 쪽으로 제출하려고 합니다.
Flex 공부도 할 겸, UI 는 레일스 + Flex 쪽으로 생각하고 있습니다.
사실 그래프 컴포넌트 등이 있는 Flex 로 하는 게 마감까지 맞출 수 있을 같더군요.
현재 확정 인원은 3명이고, 가능하기는 최대 5명까지 가능하니 주변에 떡밥 좀 뿌리고 다니고 있습니다;;

다들 학생이고 주중에는 회사 다니기에 주말밖에 시간이 안 나긴 하지만;;
되는 데까진 열심히 해봐야 겠습니다.

이번 주말 쯤엔 서점가서 Flex 책 좀 뒤져봐야 겠군요.

Ps. 이번 기회에 Redmine 좀 써보면 되겠군요. :)
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

tags

F/OSS, flex, Ruby, 공개SW, 공모대전, 오픈소스, 프로젝트

posted at

2008/08/13 21:54


POST : 프로그래밍/개발

Flex와 Rails, 그리고 REST

이 글은 작업 중에 있는 글입니다.
차후에 설명을 붙이도록 하고 우선 소스만 올려둡니다.

Internal Action Script 가 포함된 Flex mxml 파일

<?xml version="1.0"?>
<!-- 게시판 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="svcPosts.send();"
>
    <mx:HTTPService id="svcPosts" url="http://localhost:3000/posts.xml" method = "GET" resultFormat="e4x" result="postsResultHandler(event)" fault="postsFaultHandler(event)">
    <mx:request>
        <limit>20</limit>
    </mx:request>
    </mx:HTTPService>
    <mx:HTTPService contentType="application/xml"
                     id="svcCreatePost"
                     url="http://localhost:3000/posts"
                     useProxy="false" method="POST">
        <mx:request xmlns="">
            <post>
                <name>{tAuthor.text}</name>
                <subject>{tSubject.text}</subject>
                <body>{tBody.text}</body>
            </post>
        </mx:request>
    </mx:HTTPService>
    <mx:HTTPService id="svcDeletePost"
                           result="svcPosts.send();"
                           url="http://localhost:3000/posts"
                           method="POST"
                           useProxy="false"/>
    <mx:HTTPService id="svcEditPost"
                           result="svcPosts.send();"
                           url="http://localhost:3000/posts"
                           method="POST"
                           useProxy="false">                          
        <mx:request xmlns="">
            <post>
                <name>{oldAuthor.text}</name>
                <subject>{oldSubject.text}</subject>
                <body>{oldBody.text}</body>
            </post>
        </mx:request>                          
    </mx:HTTPService>
    <mx:Style>
        Panel { font-size: 12pt }
    </mx:Style>   
    <mx:Script>
    <![CDATA[
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.controls.Alert
    import mx.events.CloseEvent;
   
    [Bindable]
   
    private var posts:XML;
   
    public function postsResultHandler(event:ResultEvent):void
    {
        posts = event.result as XML
        //Alert.show(posts);
    }
   
    public function postsFaultHandler(event:FaultEvent):void
    {
        Alert.show(event.fault.message, "Could not load posts!");
    }

    private function deleteHandler(event:Event) : void
    {
      Alert.show("정말 이 항목을 삭제하시겠습니까?", "포스트 삭제", 3, this,
      function(event:CloseEvent):void
      {
        if (event.detail==Alert.YES)
            svcDeletePost.url = 'http://localhost:3000/posts/'+dgPosts.selectedItem.id+'.xml';
            svcDeletePost.send({id: dgPosts.selectedItem.id, _method:'DELETE'});
       });
    }

    ]]>
    </mx:Script>   

    <mx:Panel title="Flexible Board" height="100%" width="100%"
        paddingTop="10" paddingLeft="10" paddingRight="10">

        <mx:Label width="100%" color="black"
            text="게시판입니다."/>

        <mx:DataGrid id="dgPosts" width="100%" height="100%" rowCount="20" dataProvider="{posts.post}">
            <mx:columns>
                <mx:DataGridColumn dataField="id" headerText="No" width="40" textAlign="center" />
                <mx:DataGridColumn dataField="name" headerText="이름" width="100" textAlign="center" />
                <mx:DataGridColumn dataField="subject" headerText="제목"/>
                <mx:DataGridColumn dataField="created_at" headerText="글 쓴 날짜" width="150" textAlign="center" />
                <mx:DataGridColumn dataField="updated_at" headerText="변경된 날짜" width="150" textAlign="center"/>
            </mx:columns>
        </mx:DataGrid>

        <mx:Form width="100%" height="100%">
            <mx:FormItem label="이름">
                <mx:TextInput text="{dgPosts.selectedItem.name}" id="oldAuthor" />
            </mx:FormItem>
            <mx:FormItem label="제목">
                <mx:TextInput text="{dgPosts.selectedItem.subject}" id="oldSubject" />
            </mx:FormItem>
            <mx:FormItem label="글 쓴 날짜">
                <mx:Label text="{dgPosts.selectedItem.created_at}"/>
            </mx:FormItem>
            <mx:FormItem label="변경된 날짜">
                <mx:Label text="{dgPosts.selectedItem.updated_at}"/>
            </mx:FormItem>           
            <mx:FormItem label="내용">
                <mx:TextArea width="400" height="100" text="{dgPosts.selectedItem.body}" id="oldBody" />
            </mx:FormItem>
            <mx:Button label="글 수정"
                   click="svcEditPost.url='http://localhost:3000/posts/'+dgPosts.selectedItem.id+'.xml';svcEditPost.send({_method:'PUT'});svcPosts.send();"/>
            <mx:Button label="글 삭제"
                   click="deleteHandler(event);"/>                  
        </mx:Form>
       
        <mx:Form width="100%" height="100%">
            <mx:FormItem label="이름">
                <mx:TextInput id="tAuthor" />
            </mx:FormItem>
            <mx:FormItem label="제목">
                <mx:TextInput id="tSubject" />
            </mx:FormItem>
            <mx:FormItem label="내용">
                <mx:TextArea id="tBody" width="400" height="100"/>
            </mx:FormItem>
            <mx:Button label="글 등록"
                   click="svcCreatePost.send();svcPosts.send();"/>
        </mx:Form>
       
        <mx:ControlBar horizontalAlign="center">
            <mx:Button label="새로 고침" click="svcPosts.send();"/>
        </mx:ControlBar>
    </mx:Panel>
</mx:Application>       

레일스 어플리케이션의 DB 스키마
create_table "posts", :force => true do |t|
    t.string   "name"
    t.string   "subject"
    t.text     "body"
    t.datetime "created_at"
    t.datetime "updated_at"
end

레일스 어플리케이션 컨트롤러(REST)
class PostsController < ApplicationController
  # GET /posts
  # GET /posts.xml
  def index
    @posts = Post.find(:all, :order => 'created_at desc')

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @posts.to_xml(:dasherize => false) }
    end
  end

  # GET /posts/1
  # GET /posts/1.xml
  def show
    @post = Post.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @post.to_xml(:dasherize => false) }
    end
  end

  # GET /posts/new
  # GET /posts/new.xml
  def new
    @post = Post.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @post.to_xml(:dasherize => false) }
    end
  end

  # GET /posts/1/edit
  def edit
    @post = Post.find(params[:id])
  end

  # POST /posts
  # POST /posts.xml
  def create
    @post = Post.new(params[:post])

    respond_to do |format|
      if @post.save
        flash[:notice] = 'Post was successfully created.'
        format.html { redirect_to(@post) }
        format.xml  { render :xml => @post.to_xml(:dasherize => false), :status => :created, :location => @post }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @post.errors, :status => :unprocessable_entity, :dasherize => false }
      end
    end
  end

  # PUT /posts/1
  # PUT /posts/1.xml
  def update
    @post = Post.find(params[:id])

    respond_to do |format|
      if @post.update_attributes(params[:post])
        flash[:notice] = 'Post was successfully updated.'
        format.html { redirect_to(@post) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @post.errors, :status => :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.xml
  def destroy
    @post = Post.find(params[:id])
    @post.destroy

    respond_to do |format|
      format.html { redirect_to(posts_url) }
      format.xml  { head :ok }
    end
  end
end

생성된 SWF
생성된 SWF 파일 결과


top

tags

flex, Rails, rest, Ruby on Rails, 개발, 레일스, 루비, 삽질, , 프로그래밍

posted at

2008/08/13 09:08


POST : 프로그래밍/개발

우분투 Hardy에서 Phusion Passenger(A.K.A mod_rails) 설정하기

설치
우선 Phusion Passenger (A.K.A mod_rails)를 설치합니다.
sudo gem install passenger

우분투에서는 설치 후 패스가 제대로 걸려 있지 않습니다.
/var/lib/gems/1.8 아래에 설치가 되더군요.
아래와 같이 아파치 모듈을 설치하는 명령어를 실행합니다.
(apache2-prefork-dev 같은 아파치 개발 패키지가 필요할지도 모릅니다.)
sudo /var/lib/gems/1.8/bin/passenger-install-apache2-module

엔터 몇 번을 치면 자동으로 모듈을 빌드하고 설치를 끝마칩니다.
그리고 아래와 같은 설정을 /etc/apache2/mods-availabe/mod_rails.load 라는 파일을 만들어 놓습니다.
LoadModule passenger_module /var/lib/gems/1.8/gems/passenger-2.0.3/ext/apache2/mod_passenger.so
PassengerRoot /var/lib/gems/1.8/gems/passenger-2.0.3
PassengerRuby /usr/bin/ruby1.8

쉘에서 아래와 같은 명령으로 mod_rails 모듈을 활성화 시킵니다.
sudo a2enmod mod_rails

그리고 아래와 같이 아파치 설정을 합니다.
전 포스팅에서 다뤘던 redmine 을 예제로 합니다.

우선 /etc/apache2/sites-enable/default 파일을 아래에 아래와 같이 수정합니다.
<VirtualHost *>
  ServerName www.yourdomain.com
  DocumentRoot /home/redmine/public
  RailsEnv development
  ....(이하 생략)
</VirtualHost>

아파치를 설정을 다시 불러들입니다.
sudo /etc/init.d/apache2 force-reload

이걸로 설정이 끝났습니다.
다른 어떤 배포 환경보다도 간단하게 설치/설정이 가능합니다.
nginx+몽그렐 클러스터, 아파치+프록시 밸런서+몽그렐 클러스터 등등의 설정에 비하면 정말 간단해진 것을 알 수 있습니다.

우아한 재시작
레일스 어플리케이션을 구동하다 보면 새로운 모델을 추가한다던가 새로운 플러그인을 설치한다던가, 웹 서버를 재시작해야 할 일이 종종 생깁니다.
기존에는 우아하게 재시작하기 위해서 seesaw 와 같은 gem으로 몽그렐 클러스터를 관리했었는 데, mod_rails 는 한 술 더 뜹니다.  그저 어플리케이션 디렉토리에서 아래와 같은 명령어면 됩니다.
touch tmp/restart.txt

이렇게 restart.txt 파일만 만들어 놓으면 접속이 있을 때, 새로 레일스 설정을 불러들입니다.

어느 정도 mod_rails 를 이용하여 어플리케이션을 돌려봤는 데, 성능도 좋고 정말 안정적으로 돌아갑니다.
예전 초창기에 FCGI 썼을 때의 악몽(정말 이유를 알 수 없는 500에러...) 따위는 이제 생각하지 않아도 됩니다.
게다가 서버 재시작을 위해서 루트 권한도 필요없으니 한 번 설정만 해 놓으면 사용자 계정에서 무리없이 쓸 수도 있구요.
루비의 배포환경도 나날이 발전하고 있습니다.  아직 완벽해졌다고는 할 수 없지만, 이 정도만 되고 꽤나 편리해 진 셈이지요.
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

POST : 프로그래밍/개발

Flex 그리고 웹에 대한 짧은 생각

redmines 는 주말쯤에 시간이 날 때, 다뤄보기로 하고 이번엔 Flex에 대한 생각을 정리하려 합니다.
왜 갑자기 Flex 냐 하면.. 제가 새 직장을 얻게 되어서 앞으로 Flex를 가지고 벌어 먹고 살게 되기 때문이죠.

이번 주는 실제 Flex를 다루지는 않았고, 약간 실제 프로젝트와는 거리가 있는
일종의 수습 기간 중 테스트로서 차후에 쓰이게 될 지도 모르는 커스텀 ssh/sftp 서버를 만들었습니다.
(Python, Paramiko 라이브러리로 제작했는데 이것도 기회가 되면 블로그에 정리해야 겠습니다.)
생각보다 일찍 완성이 되어서 Flex 공부하는 셈 치고, 이거저것 만져보고 rails 와 붙여보는 작업을 해 봤습니다.

퇴근 시간 전까지 잠깐 시간내서 만들어 본거라 거의 맛만 본 수준인데,
만들어 본 어플리케이션은 간단한 게시판의 형태로 글 쓰기, 수정, 삭제 까지는 못 만들었고;;
그냥 리스트만 가져와서 화면에 출력해 주는 수준이었습니다.

서버 사이드로는 간단하게 Rails 프로젝트가 REST Web Service 를 서비스하고 있고,
클라이언트 사이드에서 Flex가 작동하여 HTTP Request 를 이용해서 XML 형태로 데이터를 받아오고
리스트를 구성해 화면에 출력해 주는 형태로 작동하게 했습니다.
Flex 에서 기본으로 제공하는 디자인은 깔끔했고 애니메이션 효과도 훌륭했고,
액션 스크립트의 웹 서비스 클라이언트는 REST 도 잘 지원되고 Ajax와 같이 귀찮은 작업도 거의 없고..
오~ 이만하면 훌륭합니다.  조금 반응이 느리고 무거워 보인다는 단점 외에는 별다른 흠 잡을데가 없더군요.

하지만 아무리 Flex 의 기능이 훌륭하고 멋지다고 해도, 어떻게 보면 결국은 고품질의 swf 를 찍어내기 위한 거대한 프레임워크일 수 밖에 없더군요.
완성되어 나와진 html 에는 swf를 embed 하는 태그와 왜 있는지 잘 모르겠는 iframe 뿐이고..
과연 이것이 웹을 올바른 방향으로 이끄는 것인가에 대한 의문이 들더군요.

좀 쓰잘데기는 없지만 웹이 나아가야할 올바른 방향은 무엇인가에 대한 이야기는 예전에도 생각했던 적이 있습니다.
초창기의 웹은 분명 연결된 문서의 형태였습니다.  하지만 지금의 웹은 그러한 모습이라고는 보기 힘듭니다.
블로그와 위키 정도만이 그 형태를 유지할 뿐 거의 어플리케이션의 형태로 가고 있다고 보고 있습니다.
Ajax 역시 그 움직임을 가속화 시키기도 했구요.

그렇다고 웹이 어플리케이션으로 가게 되는 것인가 라고 생각을 해보면 그것 또한 끔찍한 모습입니다.
화려하고 동적인 페이지를 위해서 실제 얻고자 하는 정보와 무관한 큰 크기의 리소스들(Ajax 에는 큰 덩치의 JS 프레임워크, Flex 등의 swf 파일)을 받아야 한다니..
사실 모뎀 말고, 초고속 인터넷이 등장한 후 분명 통신의 속도도 빨라졌고, 사용하는 컴퓨터의 사양도 좋아졌지만,
불필요하게 웹의 덩치도 그것에 맞추어져 예전이나 지금이나 웹의 속도는 별로 빨라지지 않았다는 느낌도 듭니다.
그것 뿐이겠습니까.. 만약 Flex나 Silverlight 런타임 플러그인 위에서 돌아가게되는 구글을 통해 내용 검색을 할 수도 없게 되겠지요. 그렇게 되면 점차 시맨틱 웹이라는 것의 의미는 퇴색되게 되겠지요.

하지만, 그렇다고 해서 연결된 문서의 형태로 웹이 남아있어야 한다고 생각하지는 않습니다.
확실히 웹이 어플리케이션화 하면서 재미가 있었지고 사람들의 생활을 이롭게 한 것은 사실이니까요.

그래서 근본적인 취지에 맞게 웹 본래의 장점을 살려보자고 등장하던 것이 REST 였지만...
Flex 에서 REST 서비스를 이용하는 방식을 보면, 글쎄요.. 정말 REST가 답인가 하는 생각마저 들기도 합니다.

웹은 확실히 가장 성공한 TCP/IP 어플리케이션이지만..
시맨틱 웹, 웹 2.0 등등의 수식어에 여기저기 휘둘리는 웹의 모습이 왠지 안쓰러워 보입니다.

무슨 글을 쓰고 있는 지도 잘 모르겠습니다.  아주 예전에 있었던 논쟁글 몇 개 링크하고 마무리 짓습니다.
김국현 씨와 윤석찬 씨는 제가 매우 존경하는 분들입니다.
존경하는 분들의 논쟁을 보면 정말.. 즐겁기 그지 없습니다. :)

차세대 웹은 브라우저를 초월하여
반론 : 차세대 웹은 브라우저를 초월하여
반론에 대한 기록 : 차세대 웹은 브라우저를 초월하여

이올린에 북마크하기(0) 이올린에 추천하기(0)
top

tags

Ajax, flex, RIA, siverlight,

posted at

2008/08/07 21:44


POST : 프로그래밍/개발

Ruby의 프로젝트 관리 어플리케이션, Redmine - 설치

redmine의 홈페이지

오늘 아침 출근해서 이것 저것 웹 서핑하다가 우연히 redmine 의 존재를 알게 되었습니다.
Python 의 trac 처럼 위키, scm, 이슈 트래킹 시스템 등등이 포함되어 있는 통합 프로젝트 관리 어플리케이션이죠.
동아리 홈페이지에 프로젝트를 공유할 수 있는 시스템을 마련하려고 하는 차에 이 놈이 딱 눈에 들어오게 됐네요.
레일스로 만들어진 어플리케이션이라 조금 수정을 하면 다른 레일스 어플리케이션이랑 잘 붙을 것 같더군요.

우선 기능을 몇 개 살펴보면, 위에 언급한 위키, scm, 이슈 트래킹 시스템 등은 모두 사용할 수 있습니다.
더욱이 기본적으로 멀티 프로젝트가 가능하고 trac 에는 존재하지 않았었던 프로젝트 별 포럼과 파일 저장소를 지원합니다.
단순히 프로젝트 관리 기능에만 충실했던 trac 과는 달리 뉴스, 문서 관리 시스템 등 일종의 커뮤니티 및 배포 사이트로서의 기능이 포함되어 있습니다.

일단 한 번 설치를 해 봅시다.
우분투 8.10 데스크탑 버젼을 기준으로 설명합니다.

우선 subversion 클라이언트가 설치되어 있지 않으신 분은
sudo apt-get install subversion
으로 subversion 클라이언트를 준비합시다.

다음은 최신 stable 버젼을 저장소에서 export 합니다.
svn co http://redmine.rubyforge.org/svn/branches/0.7-stable redmine-0.7

디렉토리로 이동 후 webrick을 실행합니다.
cd redmine-0.7
./script/server

제 경우는 레일스를 2.1.0 버젼으로 업데이트 했는 데 config/boot.rb 가 버젼이 맞지 않는다고 하더군요.
redmine 은 레일스 2.0.2 버젼을 필요로 합니다.
rake rails:update

명령으로 boot.rb 를 최신 버젼으로 업데이트 시킬 수 있습니다.
레일스가 설치되지 않으신 분은
sudo gem install -v=2.0.2 rails
로 2.0.2의 버젼을 설치하시던가, 최신 버젼의 레일스를 설치하시고 저처럼 아래와 같은 작업을 하시면 됩니다.

config/environment.rb 를 열어서, 아래와 같은 부분에서 RAILS_GEM_VERSION을 현재 자신이 사용하고 있는 레일스의 버젼과 맞추어 줍시다.
RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION

다음은 데이터 베이스 설정입니다.
저는 mysql을 이용하므로 mysql 서버에 접속해 데이터 베이스를 만들어 줍니다.
 create database redmine_development default character set utf8;
 create database redmine_production default character set utf8;
 create database redmine_test default character set utf8;

사실 production 환경으로 돌리는 것이 가장 나을 거고 그러면 redmne_production 만 만들어 주면 됩니다.
기본으로는 development 환경으로 서버가 돌아가게 되는 데, config/environment.rb 등에서 RAILS_ENV 를 'production'으로 변경하면 production 환경으로 돌아가게 됩니다. 저는 다른 프로그램들과 연동시킬 생각이라 development 로 돌리기로 했습니다.

다음은 config/database.yml을 수정합니다.
cp config/database.yml.example config/database.yml

로 샘플 설정을 복사하시고,  db 이름, db user 이름, db user 패스워드 등을 잘 설정하시면 됩니다.
우분투의 경우 mysql 소켓의 위치가 rails 기본값과는 달라서 아래와 같이 해 주거나 혹은 mysql gem 을 설치하면 된다고 합니다.

development:
  adapter: mysql
  database: redmine_development
  host: localhost
  username: root
  password:
  encoding: utf8
  socket: /var/run/mysqld/mysqld.sock


./script/server

웹 서버를 돌려보려 하면, rfpdf 플러그인이 에러를 냅니다.(레일스 2.1 기준)

/home/alice/redmine/redmine-0.7/vendor/plugins/rfpdf/init.rb 의 소스 중
ActionView::Base::register_template_handler 'rfpdf', RFPDF::View

을 아래와 같이 수정합니다.

ActionView::Template::register_template_handler 'rfpdf', RFPDF::View

그래도 아직 에러를 내는군요.;;
app/controllers/application.rb 에 제일 첫째 줄에
require 'redmine'
이라고 적어줍시다.

그리고 rake!
rake db:migrate

rake 중에도 또 에러가 나는데..
db/migrate/072_add_enumerations_position.rb
db/migrate/078_add_custom_fields_position.rb
파일의 each_value 라는 메소드를 그냥 each로 바꿔 줍니다.

rake가 끝나면 마지막으로 webrick을 실행시켜 보기위해
./script/server
로 서버를 실행시킵니다.

그리고 localhost:3000 으로 확인해보면 끝!
redmine 의 시작 페이지

심플하다 못해 썰렁해서 왠지 모를 허무감마저 든다.


심플하다 못해 썰렁한 디자인의 redmine 첫 페이지가 나오네요.
이거 삽질하다 보니 그냥 레일스 2.0.2에다 설치하거나 redmine 개발 버젼을 설치할 걸 하는 후회도 좀 드네요. :)
그래도 굳이 난 레일스 2.1에 stable 버젼을 쓰겠다고 고집하시는 분이 계시면 이 글이 도움이 되었으면 하네요.
좀 사용해보고 trac과 비교도 해보고 하려고 했는데, 설치까지만 하도록 하고 다음 포스팅거리로 남겨둬야겠습니다.
사용기 전에 설치편 번외편;; 정도로 mod_rails, svn 연동을 다룰까합니다. mod_rails 설정이야 별 다를 것 없겠지만 이왕 하는 김에 같이 다룰까 합니다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

POST : 프로그래밍/개발

쉽게 익숙해지지 않는 루비 문법 { 코드 블록 }

저는 루비를 제대로 공부해 본 적이 없습니다.
다만, 파이썬을 약간 다뤄본 지식으로 몇 개 레일스 프로젝트를 맡아 진행해 왔었고,
간단한 레일스 어플리케이션을 작성하기 위한 최소한의 루비 지식을 가지고 있습니다.
그렇기 때문에 아직도 익숙치 않는 루비 문법들이 많이 있고, 익숙치 않아서 자꾸 쓰기를 꺼려하는 문법들이 몇 개 있습니다.
그런 문법들의 개념을 익히고 잘 사용해 보기 위해서 한 번 정리해 보기로 했습니다.

코드 블록
루비 코드를 보게 되면서 처음으로 막히는 부분은 바로 코드 블록이었습니다.
코드 중간에 갑작스럽게 등장하는 중괄호나 do/end 키워드는 어떻게 해석해야할지 난해하기만 했습니다.
사실 지금도 루비는 초보 수준이라 코드 블록이 익숙하지는 않습니다. :)
코드 블록은 다음과 같이 쓰입니다.

object.method {
  # 루비 코드들...
}

혹은

object.method do
  # 루비 코드들...
end

메소드 뒤에는 당연히 인자들이 나열되어야 할 것인데.. 어째서 쌩뚱맞게 코드들이 나오는가?
하는 생각이 많이 들었죠.
이렇게 생각해도 되는 건지는 잘 모르겠지만..
코드 블록안의 코드들을 인자처럼 method 에 넘긴다고 생각하면 될 것 같네요.
실제로 메소드에서 인자로 요구하는 건 아니지만, 이해하기엔 그게 가장 쉽게 이해가 되더군요.

yield 키워드
위에서 인자처럼 넘긴다고 했는데, 그건 그냥 이해를 쉽게 하기 위해서 그렇게 생각하는 것이고..
실제로는 메소드안에서 yield 키워드 부분이 코드 블록으로 대체가 되는 것이더군요.
더 자세히 보면 메소드가 코드의 일부분을 코드 블록에게 양보(yield)한다는 느낌일까요.

def yield_test
  puts "시작"
  yield
  puts "끝"
end

yield_test { puts "yield 되었음" }

의 결과는

시작
yield 되었음

이 되겠지요. yield 에서 인자를 넘길 수도 있고 코드 블록에서 리턴된 값을 받을 수도 있습니다.

def yield_test
  puts "시작"
  result = yield(10)
  puts "결과는 #{result}"
end

yield_test do |x|
  x * 5
end

시작
결과는 50

yield 키워드가 함수처럼 10 이란 수를 코드 블록으로 넘겨줬고, 코드 블록은 10을 x라는 블록안의 지역 변수로 넘겨 받았습니다.
또 코드 블록에서 수행된 x*5의 결과를 yield_test 안으로 리턴하여 yield_test의 result가 넘겨받았음을 알 수 있습니다.

each 메소드
그 의미도 잘 모르고 계속 써 왔었던 Array 클래스의 each 메소드가 코드 블록을 보고 나니 다시 보이기 되더군요.
그냥 원래 그런 형태로 쓰는 거다 정도로만 생각하고 있었는데, yield 와 코드 블록을 이해할 수 있는 대표적인 예가 each 였네요.

[1,12,20,56].each { |i| puts i* 10 }

10
120
200
560

each는 Array 에서 한 원소씩 돌아가면서 계속 그 원소의 값을 인자로 yield를 하는 형식이겠죠.
yield에서 넘긴 인자를 코드 블록이 받아서 반복하는 형태의 가장 자주 쓰이는 코드 블록/yield의 예라고 할 수 있겠네요.

--
사실 최근에 취업과 관련해 면접을 보면서, rails 프로젝트를 진행한 것을 보고 루비를 잘 아시는 면접관 분이
루비와 레일스에 관련한 질문을 몇 개 하셨는데, 코드 블록에 대한 질문을 제대로 답변하지 못한 적이 있었습니다.  그래서 제대로 공부도 할겸 책도 찾아보고 인터넷 사이트도 뒤져보면서 알아보고 개념을 익히게 됐네요.
다음번에도 비슷하게 개념이잘안 잡힌 루비의 문법 등이 있으면, 정리해서 포스팅할 계획입니다.
이번 기회에 루비 공부도 확실히 해 두는 것이 좋을 것 같아서요. :)
이올린에 북마크하기(0) 이올린에 추천하기(0)
top

tags

code block, Ruby, 루비, 코드 블록, 프로그래밍

posted at

2008/08/03 01:26


POST : 프로그래밍/개발

REST 와 레일스

레일스를 공부하기 시작한지도 벌써 1년이 다 되어가네요.
1년동안 사용한 것 치고는 크게 실력이 늘지는 않았지만, 이제야 어느 정도 감이 잡히고 있습니다.
레일스로의 입문은 쉽지만 어느 정도 파고들다 보면 새로 공부할 것이 많이 생기기도 합니다.
이제부터 이 블로그에 하나 하나씩 레일스와 관련된 지식들을 정리해 보려 합니다.
그 첫번째로 REST와 rails에 관련한 글로 시작합니다.

REST
우선 REST란 무엇인가 부터 짚고 넘어가야겠죠.
자세히 설명하기엔 실력도 부족하고, 더 좋은 설명들이 인터넷에 많기 때문에 아래의 링크로 대체 합니다.
REST가 무엇인지에 대해 굉장히 이해하기 쉽게 쓴 글입니다.

내가 아내에게 REST를 어떻게 설명했는가

간단히 말해서 리소스(표현의 대상)라는 것에 대해 URI와 HTTP METHOD로
그 리소스의 표현(html,xml 등등..)에 접근/제어하는 형식의 웹 아키텍쳐이죠.
간단히 말한다고는 했지만 전혀 간단하지는 않아 보이네요 :)

RAILS 2.0 의 scaffold
제가 레일스를 공부하는 중에 커다란 변화가 하나 있었습니다.
그건 레일스의 버젼이 1.2에서 2.0으로 업그레이드 했다는 점이었죠.
제가 2.0 버젼의 레일스를 쓰면서 가장 처음으로 당황했던 것은 바로
scaffold 가 생성해주는 코드였습니다.

/:controller/:action/:id 식의 라우팅이 아닌 다른 방식의 라우팅이라던가..
알 수 없는 repond_to 메소드에..
:url => { :controller => 'controller_name', :action => 'action_name' } 식이 아닌 url의 표현들이 꽤 낯설었었죠.
아래에 몇 개의 메소드만 붙여넣어 봅니다.
# POST /resources
# POST /resources.xml
def create
  @resource = Resource.new(params[:resource])

  respond_to do |format|
    if @resource.save
      flash[:notice] = 'Resource was successfully created.'
      format.html { redirect_to(@resource) }
      format.xml  { render :xml => @resource, :status => :created, :location => @resource }
    else
      format.html { render :action => "new" }
      format.xml  { render :xml => @resource.errors, :status => :unprocessable_entity }
    end
  end
end

# GET /resources/1
# GET /resources/1.xml
def show
    @resouce = Resource.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @resource }
    end
end

# DELETE /resources/1
# DELETE /resources/1.xml
def destroy
  @resource = Resource.find(params[:id])
  @resource.destroy

  respond_to do |format|
    format.html { redirect_to(resources_url) }
    format.xml  { head :ok }
  end
end

시작은 routes.rb 부터...
레일스에서 REST의 시작은 config/routes.rb 로부터 시작합니다.

map.resources :posts

이 한 라인을 추가 하면, posts 리소스에 접근하기 위한 URI 들이 설정이 됩니다.

GET /posts
POST /posts
GET /posts/new
GET /posts/:id/edit
GET /posts/:id
PUT /posts/:id
DELETE /posts/:id


위에서부터 각각 PostController의 index, create, new, edit, show, update, destroy를 호출합니다.
그리고 뷰에서는 posts_url, new_post_url, post_url(@post), edit_post_url 등의 헬퍼를 사용해서 url을 표현할 수 있습니다.

또한 액티브레코드의 has_many 관계처럼 routes.rb 에서도 비슷하게 표현해 줄 수 있습니다.

map.resources :posts, :has_many => :comments

마찬가지로 아래처럼 라우팅이 설정이 되고, 각각의 헬퍼가 만들어 집니다.

GET /posts/comments
POST /posts/comments
GET /posts/comments/new
GET /posts/:post_id/comments/:id/edit
GET /posts/:post_id/comments/:id
PUT /posts/:post_id/comments/:id
DELETE /posts/:post_id/comments/:id

이 때의 헬퍼의 이름들은 comments_url(@post), new_comments_url(@post), comment_url(@post,@comment), edit_comment_url(@post,@comment) 등이 됩니다.

CRUD(Create, Read, Update, Destroy) 외의 액션에 대해 url을 만들어 주고 싶을 때엔 :collection 과 :member를 이용할 수 있습니다

map.resources :posts :member => {:recommend=>:put}
map.resources :posts, :collection => {:manage=>:get}

member의 경우는 /posts/:id/recommend 와 같이 하나의 리소스에 해당하는 액션일 때,
collection은 /posts/manage 같이 모든 리소스에 해당하는 액션일 때 사용합니다.
위의 :put과 :get 은 허용하는 http method를 의미하고 :any라고 쓰면 모든 http method(:get, :post, :put, :delete)를 허용합니다.

respond_to do |format|
그럼 scaffold의 각 메소드 끝에 나와있는 respond_to 에 대해서 살펴봅시다.
사실 위의 URI 매핑에서 생략된 것이 하나 있습니다.
바로 :format 이라는 건데, 리소스를 어떤 형태로 표현할 것인가에 대해서 요청합니다.
사실 위의 7개의 라우팅은 아래와 같은 또 다른 형태의 매핑이 있습니다.

GET /posts.:format
GET /posts/:id.:format
GET /posts/new.:format
GET /posts/:id/edit.:format
...

위와 같은 라우팅 규칙을 통해서 /posts.html, /posts.xml, /posts/1.html, /posts/1.xml 등의 요청이 커버됩니다.
/posts/1.xml 같은 요청의 경우 format 이라는 메소드는 xml 을 리턴하게 됩니다.
respond_to do |format| 에서 format 이 xml일 경우는 format.xml 에 해당하는 블럭을 실행하게 됩니다.

다시 한 번 말씀드리면 위의 REST 설명에도 잘 나와있듯이 리소스의 표현은
html 외의 다른 여러가지가 될 수 있습니다.
가장 주로 쓰이는 예로는 xml이 있겠지요. text가 될 수도 있고, pdf가 될 수도 있겠지요.
오픈API 같은 웹 서비스를 구현할 때 리소스의 표현을 xml로 이용하면 쉽게 구현할 수 있겠죠.

위의 scaffold 의 코드에서는 format이 html일 경우는 생략이 가능한데..
생략하게 되면 repond_to에서 디폴트로 가장 첫 라인의 format을 선택하기 때문이라고 하더군요.

----

REST와 레일스라고 거창하게 시작을 했는 데 결국은 레일스 2.0 scaffold 에서 생성한 컨트롤러 분석이 되버렸네요.
그래도 주위에 레일스 2.0의 접근을 어려워하는 분들이 있어서, 그런 분들에게 도움이 되는 글이었으면 좋겠네요.

이올린에 북마크하기(0) 이올린에 추천하기(0)
top

tags

Rails, rest, Ruby on Rails, 레일스, 루비, , 프레임워크, 프로그래밍

posted at

2008/07/31 21:10


CONTENTS

Dragonkun in Tistory
BLOG main image

RSS 2.0Tattertools
공지 아카이브
최근 글 최근 댓글 최근 트랙백
카테고리 태그 구름사이트 링크