Languages/Ruby or Rails2008.10.15 16:10

지난 번 글에서 RESTful 프로그래밍을 할 때 구현해야 할 CRUD 연산 중 CREATE를 구현하기 위해 Rails 서버측 코드를 어떻게 고쳐야 하고, jQuery 코드를 어떻게 고쳐야 하는지를 살펴봤습니다. 그럼 오늘은 RETRIEVE, UPDATE, DELETE 연산을 어떻게구현하는지 살펴보도록 하죠.

RETRIEVE 연산은 두 가지가 있습니다. ID를 주고 그 ID에 해당하는 리소스를 조회하는 연산, 그리고 모든 리소스를 전부 조회하는 연산이 바로 그것이죠. 지난 시간에 보았던 location이라는 리소스의 경우를 생각해 본다면, 모든 location을 전부 조회하는 연산이 있을 수 있고, 특정한 location만을 조회하는 연산이 있을 수 있습니다. 그런데 가만히 생각해 보면 모든 location을 전부 조회하는 것은 그다지 바람직하지 않습니다. 뭔가 조건을 줄 수 있도록 하는 것이 좋죠.

그러니, rails의 scaffold 명령이 생성한 코드들 조금 고쳐 주어야 합니다. 아래의 코드를 보시죠.

  # GET /locations
  # GET /locations.xml
  def index
    if ( params[:elementid] )
      @locations = Location.find(:all, :conditions =>
                          [ "elementid= ?", params[:elementid] ]);
    else
      @locations = Location.find(:all)
    end

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @locations }
      format.js { render :json => @locations }
    end
  end

'모든 location을 조회하는 연산'은 LocationsController의 index 메소드에 의해 처리됩니다. 이 메소드에 전달되는 params 해쉬에 :elementid를 키로 하는 값이 있는 경우, 그 값을 조건으로 하여 location 리소스들을 검색하도록 코드를 변경했습니다.물론 그런 값이 없는 경우에는 하던 대로 하면 되구요.

클라이언트 코드는 다음과 같이 작성하면 됩니다. HTTP 메소드로 GET을 사용할 것이기 때문에 $.getJSON을 사용해 구현할 수 있습니다.

var loadLocations = function(options, callback) {
  $.getJSON('locations', {elementid: options.elementid}, function(data) {
    $.each( data, function(index, d) {
      callback( d );
    });
  });
}

가져온 location 리소스 (json 형식입니다) 하나 하나를 callback 함수의 인자로 넘겨 처리하도록 하고 있습니다. 이 때 전달받은 데이터의 각 필드들을 접근하기 위해서는 d.location.id 뭐 이런 식으로 해야겠죠. 그런 부분은 일단 코드에서 다 뺐습니다. 구현하시는 분들이 알아서 하셔야 하는 부분이라서요.

어쨌든, RETRIEVE쪽은 이렇게 구현할 수 있습니다. RETRIEVE 연산 중 나머지 하나 (특정한 ID에 해당하는 리소스만들 조회하는 부분)는 다루지 않겠습니다. 여기까지만 아셔도 충분히 하실수 있으리라 믿고...

그럼 이제 CRUD 중 U, 즉 UPDATE를 하는 쪽을 알아보도록 하죠.

RETRIEVE를 통해 각각의 location 리소스에 할당된 id를 다 알아낼 수 있다는 것에 우선 유념하도록 합시다. 일단 rails 컨트롤러쪽 코드를 보면 다음과 같습니다.

  # PUT /locations/1
  # PUT /locations/1.xml
  def update
    @location = Location.find(params[:id])

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

클라이언트가 참조한 URL에 붙어있는 ID값을 사용해 갱신할 location 객체를 찾은 다음, 갱신합니다. format.json이 어떻게 구현되어 있는지를 잘 보시기 바랍니다. 클라이언트가 json 데이터를 요구한 경우, format.json 안에서 head :ok만 해버리면 설사 rails 서버 쪽에서는 데이터베이스 갱신을 제대로 했다고 하더라도 웹 브라우저는 (그러니까 클라이언트) 이를 오류로 간주한다는 문제가 있습니다.

이 문제를 피해가기 위해서는 서버 쪽에서 비어있는 json 객체라도 만들어 클라이언트 쪽으로 던져줘야 합니다. :statis의 값은 저처럼 :accepted로 해도 되고, :ok로 해도 되겠죠.

여기에 대한 클라이언트 측 코드는 다음과 같습니다.

var updateLocation = function( options ) {
         $.ajax( {
            url: 'locations/' + options.id,
            type: 'put',
            data: {
              'location[x]': options.pageX,
              'location[y]': options.pageY,
              'location[width]': options.width,
              'location[width]': options.width
            },
            dataType: 'json'
          }
        );
}

type:의 값이 put이 되었다는 것 뺴고는 별거 없는 코드니까 설명은 생략하겠습니다. URL에 id를 붙여 주어야 한다는 점만 주의하면 되겠습니다. 그래야 어떤 아이템을 update할 것인지 서버가 알수 있을테니까요.

그럼 이제 CRUD 중 마지막 연산, DELETE를 한번 살펴보죠. 역시 rails 서버측 코드를 먼저 보겠습니다.

  # DELETE /locations/1
  # DELETE /locations/1.xml
  def destroy
    @location = Location.find(params[:id])
    @location.destroy

    respond_to do |format|
      format.html { redirect_to(locations_url) }
      format.xml  { head :ok }
      format.json { render :json => {}, :status => :accepted }
    end
  end

코드는 UPDATE의 경우와 비슷하므로, 설명은 생략하고 바로 클라이언트 코드로 넘어가겠습니다.

var deleteLocation = function( option ) {
       $.ajax( {
          url: 'locations/' + option.id,
          type: 'delete',
          dataType: 'json'
        }
      );
};

역시 URL에 삭제될 리소스의 ID가 붙어 들어간다는 것과, type이 delete로 지정되었다는 것을 제외하면 크게 새로울 것은 없는 코드입니다.

신고
Posted by 이병준
TAG , ,

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