전에 이어서.... 다시 한번 말하지만 이 모든 자료는 (Easy start!) 웹 개발 2.0 루비 온 레일스(저자 : 황대산, 출판사: 에이콘)을 바탕으로 쓰여진 것들이고, 혹시라도 문제가 생길 시에는 전부 삭제할 것이다. 이번에 다룰 것은 MVC 모델에서 C의 역할, 즉 웹 어플리케이션 내부의 컨트롤러부분이다. 액션 컨트롤러 : 이제까지의 액션 레코드는 아무래도 데이터 관리에 중점을 많이 뒀었다. 컨트롤러는 내부 로직에 관련하여 말 그대로 컨트롤 하는 부분이다. 이제 그럼 시작해볼까. 일단 컨트롤러를 한번 만들어보자. $ruby script/generate controller Users list show new create Users 뒤에 뭔가 이상한 네 녀석이 붙었는데, 이것들은 액션 메소드를 나타낸다. 액션 메소드 라는 것은 어플리케이션이 어떻게 일을 할 지를 나타내는 메소드 들이다. 좀 더 정확히 말하자면 액션 컨트롤러 클래스의 모든메소드가 액션 메소드인 것은 아니다. 액션 컨트롤러 클래스 안의 메소드 중, URL 요청에 의해 호출되는 메소드만을 액션메소드라고 부른다. 그냥 기초적인 액션 메소드들을 한번 살펴볼것이다. 1 class UsersController < ApplicationController render :controller => 'users', :action => 'new' 이 코드가 의미하는 것은 해당 메소드가 new.rhtml 템플릿 파일을 사용할 것을 지정하고 있다. :controller 옵션은 빼도, 가능한데, 그 경우에는 현재 컨트롤러를 deafult 값으로 생각한다. UsersController을 살펴보면 ApplicationController 클래스를 상속받는 것을 알 수 있다. 그래서 params, request, session 등의 메소드가 사용 가능하다. params는 HTML 폼으로부터 전송된 파라미터를 모두 해시 객체로 리턴해주는 메소드이다. 예를 들어서 http://mysirte.co.kr/users/list?page=3이라면 params[:page] 는 3을 리턴하는 것이다. 그리고 리턴값은 모두 문자열이다. 즉 저 3 역시 문자열로 저장되어있다. request 메소드는 브라우저의 http requiest를 모델링하는 Request 객체를 리턴하는데, 이 객체를 통해서 현재의http 요청이 get 요청인지, post 요청인지 알 수 있다. 만약 브라우저가 http get 메소드를 사용한다면,request.get? 이 true를 리턴할 것이다. Request 객체에는 get ? 외에도, post?, domain,port, request_uri, ssl?, remote_ip 등의 메소드가 있다. 나머지는 대충 알 수있고, request_uri는 도메인 부분을 뺀 나머지 경로주소를 리턴, remote_ip는 웹브라우저가 설치된 컴퓨터의ip주소를 리턴한다. HTML 폼 데이터의 처리 이런 hthml 코드가 있다고 하자. <form action="/articles/create" method="post"> <input name="title" type="text" /> <textarea name="body"></textarea> <input type="submit" value="입력" /> </form> 여기서 입력 버튼을 누르게 되면 정보들이 http://127.0.0.1:3000/articles/create로 전송이 된다. 그러면 그것을 어떻게 처리할 것인가 class ArticlesController < ApplicationController def new @article = Article.new end def create @article = Article.new @article.title = params[:title] @article.body = params[:body] if @article.save redirect :action = 'list' else render :action => 'new' end end ... end 이렇게 되있으면 알아서 샤샤삭하고 데이터들이 처리가 된다. params 메소드를 호출할때 html에서 입력된 데이터 폼은 해시의 형태로 다음과 같이 리턴된다. { :title => "오늘의 날씨", :body => "맑은 날씨입니다.", ...} 만약에 html 코드에서 액티브 레코드 모델의 데이터로 처리가능하다면 더 편리해질 수 있다. 다음을 보자. <form action="/articles/create" method="post"> <input name="article[title]" type="text" /> <textarea name="article[body]"></textarea> <input type="submit" value="입력" /> </form> 이런식인 경우 params의 메소드 리턴값은 다음과 같다. { :article => { :title => "오늘의 날씨", :body => "맑은 날씨입니다.", ...} ... } 이런 경우에 한방에 집어넣는 것이 가능하다. create 메소드만 살펴보자. def create @article = Article.new(params[:article]) if @article.save redirect :action = 'list' else render :action => 'new' end end new 부르고 안에 파라미터 넣고 하던 귀찮은 과정이 한방에 끝났다. 세션과 로그인 세션에 대해서는 별다른 설명을 하지 않고, 그냥 소스코드로 ㄱㄱㄱ class LoginController < ApplicationControler def login_form reset_session end def login @user = User.find_by_login(params[:login]) if @user && (@user.password == params[:password]) session[:user_id] = @user.id redirect_to :action => "index" else flash[:error] = "로그인 iD나 비밀번호가 틀렸습니다!" redirect_to :action => "login_form" end end def logout reset_session redirect_to :action => "login_form" end def index if session[:user_id] render_text "#{User.find(session[:user_id].name} 님 환영합니다!" else redirect_to :action => "login_form" end end end 여기의 코드들은 대략적으로 이해할 수 있을것으로 믿는다. 다만 flash나 session 메소드가 좀 특이할 텐데,session[:user_id] = @user.id 의 경우, session은 해시 객체를 리턴하니깐, :users_id에 이제실제 로그인한 사람의 @user_id를 넣는 것이다. 만약 nil값이면이 session값이 없는것이므로 로그인이 아직이라는것이다. 그리고 로그인에 실패하는 경우, flash 메소드가 등장하는데, flash 메소드는 Flash 객체를 리턴한다. 이 Flash 객체는 바로 다음 액션이 일어날때까지만 정보를 저장해두고, 그 뒤로는 사라진다. 혹시 세션이 필요하지 않는 경우에는 session :off 란 코드를 통해서 꺼두길 바란다. 혹시 전체적인 어플에서 사용하지 않기를 바란다면 ApplicationController 클래스에서 session :off라는 걸 선언하면 된다. 쿠키 쿠키부분은 그냥 코드만 남겨놓을 것이다. class LoginController < ApplicationController def login_form reset_session @login = cookies[:login] end def lgin @user = User.find_by_login(params[:login]) cookes[:login] = {:value => @user.login, :expire => 30.days.from_now} if @user && (@user.password == params[:password]) session[:user_id] = @user.id redirect_to :action => "index" else flash[:error] = "로그인 iD나 비밀번호가 틀렸습니다!" redirect_to :action => "login_form" end end end 여기에서 옵션이 몇개가 빠져있다. :domain => ".mysite.co.kr" 이런 경우 a.mysite.co.kr 이나, b.mysite.co.kr 이나 전부 사용할 수 있게 된다. :path => "/search" 이 경우, 쿠키는 URL이 mysite.co.kr/search로 시작되는 경우에만 서버에 보내진다. : secure => true HTTPS 프로토콜을 사용하는 경우에만 보내진다. 플래시(힘들어죽겠네) 이전 액션에서 어떤 에러가 일어났는데, http 프로토콜의 특성상, 이전것을 알 수 없기 때문에 에러 메시지를 체크할 수 없다. 그런 것을 위해서 있는 것이 플래시 이다. class UserContoller < ApplicationContorller def list @users = User.find(:all) @message = flash[:message] end def show @user = User.find(params[:id]) end def new @user. Userl.new end def create @user = User.new(params[:user]) if @user.save flash[:message] = "새로운 사용자가 추가되었습니다." redirect_to :action => "list" end end end 이렇게 해서 다음 액션에서 이전액션의 결과 등을 플래시를 통해 알 수 있게 된다. 필터 필터란 액션 컨트롤러의 액션 메소드가 실행되기 이전 또는 이후에 추가적인 작업을 할 수 있게 하는 기능이다. 이 기능이 필요한 이유는, 여러 액션 혹은 컨트롤러에 공통적으로 적용될 작업을 한 곳에서 관리할 수 있기 때문이다. before 과 after가 존재. before만 설명 class AplicationController < ActionController::Base private def check_login_status unless session[:user_id] redirect_to :controller => "login", :action => "login_form" end end end private라고 선언된 경우에는, 액션 메소드로 호출 할 수 없다. 즉. 브라우져가 콜하는 것은 못한다. 이제 이것을 어떻게 적용할 것인가.... class UsersController < ApplcationController before_filter :check_login_status ... 이렇게해서 이제 UserController에서의 액션이 요청될 시에는 언제나 check_login_status가 실행이 되게 된다. 혹시나 전부 적용하지 않고 싶은 경우에는 다음과 같이 쓰면 된다. before_filter :check_login_status, :except => [:list, :show] except 외에도 :only가 있다.
클릭
2
3 def list
4 @users = User.find(:all)
5 end
6
7 def show
8 @user = User.find(params[:id])
9 end
10
11 def new
12 @user = User.new
13 end
14
15 def create
16 @user = User.new(params[:user])
17 if @user.save
18 redirect_to :action => 'list'
19 else
20 render :action => 'new'
21 end
22 end
23 end
그냥 대충 만들어진 메소드들이다. 각 액션 메소드들에는 기본적으로 배정된 템플릿 파일이 app/views/users(여기서users는 우리가 만들기를 users라고 해서 이다)에 존재한다. 혹시나 그 기본적으로 배정된 템플릿 파일을 변경하하고싶으면 메소드의 맨 끝에서 render 메소드를 호출해야 한다.
