Categories
Ruby on Rails

[Ruby] IntelliJ에서 Rails를 이용한 간단한 방명록 만들어보기

rails_logo

요즘 열심히 레일즈 공부를 하고 있습니다. 사실 열심은 아닌것 같네요. 백문이 불여일견 뭔가 한번 해보는게 좋지 않을까 싶어 간단한 방명록을 혼자 만들어보기를 해보기로 하였습니다. 그 과정을 기록해 볼테니 저같은 시작하시는분들에게 참고 자료가 될 수 있다면 좋겠네요.

이 기록은 Rails기반의 개발이 가능한 제트브레인사의 IntelliJ 또는 RubyMine기반에서 개발한다는것을 가정하고 기록하고자 합니다. 또한 맥기반에서 개발하고 있기에 윈도우 환경과는 차이가 조금 있을수도 있습니다.

IntelliJ를 실행한 뒤에 새로운 프로젝트를 생성하기 위해 Create New Project를 선택합니다.

Ruby 플러그인을 선택한 뒤에 적절한 프로젝트를 생성합니다. 저는 그냥 대충 guestbook이라고 만들어보겠습니다.

이번엔 적절한 SDK를 선택해줍니다. 아무것도 없다면 Configure에 들어가 설치되어있는 Ruby를 선택하여 추가해 주면 됩니다.

왼쪽의 Ruby on Rails를 선택한 다음에 적절한 Rails Version을 선택해 줍니다. 아무것도 없을 경우 Install Rails Gem…을 선택하여 적절한 Rails를 설치해주면 됩니다.

이제 프로젝트가 세팅되고 자동으로 bundle install까지 실행됩니다.

이런식으로 “Your bundle is complete!”라는 문구가 보이면 프로젝트의 초기화가 끝난것입니다.

오른쪽 상단의 플레이 모양 버튼을 누르면 WEBrick 기반의 서버가 시작됩니다. 정상적으로 실행된다면 콘솔에 보이는것과 같은 로그가 출력됩니다. 이제 브라우저를 통해서 http://localhost:3000 에 접속해 보겠습니다.

위와 같은 기본 페이지를 볼 수 있습니다. 여기서 무언가 친절한 설명이 나오고 있군요. 저 설명대로 진행을 해보겠습니다.

New – Run Rails Generator를 실행해 봅니다. 간단하게 Option – G를 눌러도 됩니다.

컨트롤러를 먼저 만들까 모델을 먼저 만들까 고민을 많이 했습니다만, 가이드의 순서가 뭔가 의미가 있지 않을까(?) 생각되어 모델부터 만들어 보겠습니다. 검색을 통해 빠르게 무엇을 생성할것인지를 선택할 수 있습니다.

Generate arguments 의 내용을 참고하여 필요하다고 생각되는 항목을 적어보았습니다. 사용자의 정보인 name, email이 있고 내용을 수정 삭제하기 위한 password와 방명록 글 내용인 content를 추가하였습니다. 여기서 예시에 [ ]를 보고 대괄호를 해줘야 하는줄 알았는데 Optional의 의미더군요;;

Rails는 단수복수의 구분이 매우 중요합니다. 모델을 생성할 때 단수로 생성한것을 주의깊게 봐두세요.

오류 없이 정상적으로 필요한 것들이 생성되었습니다. DB 마이그레이션 작업을 수행하여보겠습니다. 기본적으로 Development환경에서의 데이터베이스 설정은 sqlite로 구성되어있습니다. 아쉬운데로 그냥 진행해보겠습니다.

rake 라는 명령을 사용하여 데이터베이스 마이그레이션을 진행하게 되는데 Tools – Run Rake Task…메뉴를 통해 실행할 수 있습니다. 단축키는 Option + R 입니다.

마이그레이션 시점을 선택할 수 있습니다. 일단 하나밖에 없군요. 그냥 latest migration을 선택하도록 하겠습니다.

이번에는 컨트롤러를 만들어보았습니다. 여기서 주목할 점은 컨트롤러의 이름이 복수형이라는것 그리고 액션에 7개를 추가하였습니다. 이 7개의 액션은 외울필요가 있습니다. 이후에 나올 라우팅 설정에서 리소스라는것과 연결되게 됩니다. 각각은 다음을 담당하게 됩니다.

  • index : 방명록의 모든 글을 보여줍니다.
  • new : 방명록에 새로운 글을 작성하는 HTML폼을 보여줍니다.
  • create : 방명록에 새로운글을 추가합니다. 데이터베이스에 INSERT 하는 작업을 수행합니다.
  • show : 방명록에 작성된 글중 하나의 특정한 글을 보여줍니다.
  • edit : 방명록에 작성된 글 중 하나의 특정한 글을 수정하는 HTML폼을 보여줍니다.
  • update : 특정한 글의 내용을 수정합니다. 데이터베이스에 UPDATE 하는 작업을 수행합니다.
  • destroy : 방명록에 작성된 글 중 하나의 특정한 글을 삭제합니다.

여기에 보이는 버튼들을 이용하여 서버를 종료하거나 재시작할 수 있습니다. 재시작하기 전에 라우팅 설정을 좀 살펴보겠습니다. 라우팅 설정파일은 config/routes.rb 파일을 참고하시면 됩니다. 여기서 외부의 어떤 요청을 어떤 컨트롤러에 연결해줄것인가에 대한 정의를 하게 됩니다.

음… IntelliJ께서 친절하게 자동으로 뭔가를 추가해주셨네요. 밑에 post/*들은 테스트로 해봤다가 남아있는 잔재입니다; 위의 내용을 모두 삭제하고 다음으로 변경합시다.

Guestbook::Application.routes.draw do
  resources "posts"
end

이제 서버를 새시작하고 http://localhost:3000/posts 에 접속해 봅시다.

/posts 로의 요청이 자연스럽게 PostsController의 index 액션을 타고 결과적으로 index 뷰가 출력되었습니다. 저 resources 설정이 자동으로 필요한 라우트 설정을 추가해 줍니다. 이를 확인해 보려면 rake routes를 실행해 보는 방법이 있습니다. Option + R 을 눌러 rake 실행창을 열고 routes를 실행해 봅시다.

   Prefix Verb   URI Pattern               Controller#Action
    posts GET    /posts(.:format)          posts#index
          POST   /posts(.:format)          posts#create
 new_post GET    /posts/new(.:format)      posts#new
edit_post GET    /posts/:id/edit(.:format) posts#edit
     post GET    /posts/:id(.:format)      posts#show
          PATCH  /posts/:id(.:format)      posts#update
          PUT    /posts/:id(.:format)      posts#update
          DELETE /posts/:id(.:format)      posts#destroy

Process finished with exit code 0

이것을 천천히 봐보시면 알 수 있지만 /posts/* 패스를 이용하여 기존에 생성했던 7개의 메소드에 연결해주는것을 볼 수 있습니다. 위의 내용을 해석해 보면 다음을 알 수 있습니다.

  • GET /posts 를 요청하면 방명록에 작성된 모든 글을 보여준다. (디비 SELECT)
  • POST /posts 를 요청하면 방명록에 새로은 글을 추가한다. (디비 INSERT)
  • GET /posts/new 를 요청하면 방명록에 새로운 글을 작성할 수 있는 HTML 폼을 보여준다.
  • GET /posts/:id/edit 를 요청하면 방명록에 기존에 작성된 글을 수정할 수 있는 HTML 폼을 보여준다.
  • PATCH 또는 PUT /posts/:id 를 요청하면 방명록에 기존에 작성된 글의 내용을 수정한다. (디비 UPDATE)
  • DELETE /posts/:id 를 요청하면 방명록에 기존에 작성된 글을 삭제한다. (디비 DELETE)

여기서 재미있는 점이 한가지 있는데 Prefix에 있는 값들을 레일즈안에서 마치 메소드처럼 호출하여 사용할 수 있습니다. (posts_path, new_post_path 등.. 뒤에서 설명하겠습니다) 이제 위의 기능들이 하나하나 동작하도록 고쳐보겠습니다.

일단 방명록이라고 하면 대체적으로 상단에 글쓰기 폼이 있고 그 밑으로 기존에 작성된 글들이 리스트되어 보여지는 형태입니다. 그러므로 이 프로젝트에서는 GET /posts/new 페이지는 없어도 괜찮을지 모르겠습니다. 그러면 먼저 GET /posts 에 글쓰기 폼을 추가해 보겠습니다. app/views/posts/index.html.erb의 내용을 다음과 같이 수정하였습니다. 레일즈에서 제공하는 Form Helper를 사용하였습니다. HTML 쌩코딩을 하고싶었지만 일반 HTML폼으로는 GET/POST이외에는 구현하기 어렵기 때문에 이것을 사용하는것이 좋을것 같습니다.

<h1>Guestbook List</h1>
<%=form_for :post, url: posts_path, method: :post do |f| %>
    Name : <%=f.text_field :name  %><br>
    Email : <%=f.text_field :email  %><br>
    Password : <%=f.password_field :password  %><br>
    <%=f.text_area :content  %>
    <%=f.submit %>
<% end %>

그리고 http://localhost:3000/posts에 들어가면 다음과 같은 화면을 볼 수 있습니다.

새로운 글 작성에 필요한 폼이 만들어졌습니다. 위에서 확인했었던 routes 값과 비교해 보면 POST 메소드로 posts_path에 요청을 날리게 되어있습니다.(form의 action과 method값 확인) 여기서의 posts는 routes 결과 첫번째 줄에 정의된 값입니다. 거기 정의되어있는 URI Pattern값을 반환하게 됩니다. 즉 /posts 를 반환하게 됩니다.

rake routes의 결과에서 가장 앞단에 있는 Prefix의 값은 URI Pattern에 정의되어있는 값과 매칭됩니다. 하지만 Prefix라는 명칭에서 알 수 있듯이 접두사로 쓰이게 되며 뒤에 _path 또는 _url을 붙여서 사용합니다. _path를 붙인 경우 주소의 패스값을 반환하게 되고 _url을 붙이게 되면 도메인, 포트등의 모든 주소를 붙인값을 반환하게 됩니다.

<%=posts_path %> 라고 하였으니 도메인이나 포트 정보가 제외된 형태 즉, /posts 를 반환합니다.

폼의 제출 버튼을 누르면 POST /posts 를 수행하게 될테니 routes 정보를 볼때 posts#create가 실행될것이라는것을 알 수 있습니다. create 액션을 만들어보겠습니다.

def create
  post = Post.new
  post.name = params[:post][:name]
  post.email = params[:post][:email]
  post.password = params[:post][:password]
  post.content = params[:post][:content]
  post.save
  redirect_to posts_path
end

POST로 넘어온 파라미터로 그대로 넘기는것이 가능한 이유는 HTML폼의 필드들의 name의 값과 디비(모델)의 필드명이 동일하기때문에 가능한 부분입니다.이제 http://localhost:3000/posts 에 진입하여 폼을 채우고 “제출” 버튼을 눌러봅시다.

아무런 오류없이 다시 글쓰기 폼이 보이는것을 확인할 수 있습니다. 리다이렉트가 잘 되는군요. 이제 저장된 결과를 출력해 봅시다. 먼저 PostsController (app/controllers에 존재)에 index 액션을 수정합니다.

def index
  @posts = Post.all
end

posts/index.html.erb 뷰에는 form 밑에 다음을 추가해 줍니다.

<% @posts.each do |post| %>
<div>
    <p><%=post.name%> (<%=post.email%>)</p>
    <p><%=post.content%></p>
</div>
<% end %>

이제 수정된 결과를 확인하러 가봅시다.

작성한 글이 잘 출력되어 보여지는군요. 이제 수정과 삭제 버튼을 만들어 보겠습니다. 위의 erb내용을 다음과 같이 좀 더 업데이트 해봅시다.

<% @posts.each do |post| %>
<div>
    <p>
        <%=post.id%>
        <%=link_to "수정", edit_post_path(post.id) %>
        <%=link_to "삭제", post, :method => :delete %></p>
    <p><%=post.name%> (<%=post.email%>)</p>
    <p><%=post.content%></p>
</div>
<p></p>
<% end %>

posts/edit.html.erb 뷰파일을 다음과 같이 수정합니다.

<h1>Guestbook Edit</h1>
<%=form_for :post, url: post_path(@post), method: :patch do |f| %>
    Name : <%=f.text_field :name  %><br>
    Email : <%=f.text_field :email  %><br>
    Password : <%=f.password_field :password  %><br>
    <%=f.text_area :content  %>
    <%=f.submit %>
<% end %>

PostsController의 edit, update, destroy 액션의 내용을 추가합니다.

def edit
  @post = Post.find(params[:id])
end

def update
  post = Post.find(params[:id])
  post.name = params[:post][:name]
  post.email = params[:post][:email]
  post.password = params[:post][:password]
  post.content = params[:post][:content]
  post.save
  redirect_to posts_path
end

def destroy
  post = Post.find(params[:id])
  post.destroy
  redirect_to posts_path
end

이제 기본적으로 새로운글을 추가, 수정, 삭제가 가능한 방명록(이라고 부르긴 힘들겠지만)을 만들어 보았습니다. 비밀번호 대조를 통해서 수정시 뭔가 체크를 하는 기능을 구현하고자 password를 만들었지만 그부분은 패스하겠습니다^^;

Categories
JAVASCRIPT

Prototype Javascript Framework – Form

그동안 빼먹고 있었군요. 중요도로 따지면 Element와 쌍벽을 이루는 Form에 대해서 알아보도록 합시다.
사실 웹페이지에 Form없이 이루어진 페이지를 찾기가 어려울 정도로 많이 쓰이고 있습니다. 데이터를 서버측으로 전송하기 위해서 사용할 수 있는 가장 기본적이면서 강력한 방법일테니깐요. 그 Form을 위해 만들어진 클래스에 대해 알아보겠습니다.

Form Methods —————————————————————————————————–
disable : 폼 혹은 폼 엘리먼트를 비활성화 합니다.
[code]disable(formElement) -> HTMLFormElement[/code]

예제)
[code]var form = $(‘disable-example’);
// form.disabled값에 따라 form.enable()과 form.disable()를 실행
form[form.disabled ? ‘enable’ : ‘disable’]();
form.disabled = !form.disabled;[/code]

enable : 폼 혹은 엘리먼트를 활성화 합니다.
[code]enable(formElement) -> HTMLFormElement[/code]
disable() 메서드로 비활성화 시킨 폼 및 폼 엘리먼트를 활성화 시킵니다.

findFirstElement : 숨겨지지 않고 비활성화되지 않은 첫번째 폼 컨트롤 엘리먼트를 반환합니다.
[code]findFirstElement(formElement) -> HTMLElement[/code]
이 메서드는 INPUT, SELECT, TEXTAREA 엘리먼트중에 첫번째 엘리먼트를 반환합니다. 문서상의 첫번째 엘리먼트로 반환하며 tabindex 순서는 따르지 않습니다. focusFirstElement() 메서드에서 사용합니다.

focusFirstElement : 숨겨지지 않고 비활성화되지 않은 첫번째 폼 컨트롤을 Activate 합니다.
[code]focusFirstElement(formElement) -> HTMLFormElement[/code]
findFirstElement를 사용하여 첫번째 엘리먼트를 찾아온 후 activate() 메서드를 호출합니다.

getElements : 폼의 모든 폼 컨트롤 엘리먼트를 배열로 반환합니다.
[code]getElements(formElement) -> array[/code]
주의!! SELECT컨트롤의 경우 하위 OPTION 컨트롤은 결과에 포함되지 않습니다.

getInputs : 폼의 모든 INPUT 폼 컨트롤 엘리먼트를 반환합니다.
[code]getInputs(formElement [, type [, name]]) -> array[/code]
폼의 모든 INPUT폼 컨트롤 엘리먼트를 가져옵니다. type과 name을 옵션으로 줄 수 있습니다.

예제)
[code]var form = $(‘myform’);


form.getInputs();
// -> 모든 INPUT 폼컨트롤 엘리먼트


form.getInputs(‘text’);
// -> INPUT 폼컨트롤 엘리먼트중에 type이 text인 엘리먼트


var buttons = form.getInputs(‘radio’, ‘education’);
// -> type이 radio이며 name이 education인 폼컨트롤 엘리먼트를 disable()
buttons.invoke(‘disable’);[/code]

request : form의 action 파라미터값으로 submit을 합니다.
[code]request([options]) -> new Ajax.Request[/code]
이 메서드야 말로 페이지 이동 없이 form submitting을 하게 만들어 주는 주체가 되는 메서드인것 같습니다. 폼 안의 폼 컨트롤들의 값을 모아 form의 action 파라미터에 있는 페이지로 Request를 요청합니다. 이후 결과 처리도 할 수 있습니다.



  • form에서 method 파라미터를 가지고 있다면 Ajax.Request의 method 파라미터로 전달됩니다.

  • method가 없을 경우에는 기본적으로 POST로 설정됩니다.

  • ‘키-값’의 쌍을 이루는 폼 컨트롤들의 값은 parameters 옵션에 전달됩니다.

예제)
[code]<form id=”person-example” method=”POST” action=”/user/info”>
  <fieldset><legend>User info</legend>
    <div><label for=”username”>Username:</label>
    <input type=”text” name=”username” id=”username” value=”” /></div>
    <div><label for=”age”>Age:</label>
    <input type=”text” name=”age” id=”age” value=”” size=”3″ /></div>
    <div><label for=”hobbies”>Your hobbies are:</label>
    <select name=”hobbies[]” id=”hobbies” multiple=”multiple”>
      <option>coding</option>
      <option>swimming</option>
      <option>hiking</option>
      <option>drawing</option>
    </select>
  </div>
  <div class=”buttonrow”><input type=”submit” value=”serialize!” /></div>
  </fieldset>
</form>[/code]
[code]$(‘person-example’).request();
// Request 완료~!


// 다음과 같은 방법으로 콜백함수를 사용할 수 있습니다.
$(‘person-example’).request({
  onComplete: function(){ alert(‘Form data saved!’) }
})[/code]
다른 파라미터 값을 추가적으로 사용하고 싶을경우에는 parameters인자를 사용하면 됩니다. 마찬가지로 method도 임의로 변경 할 수 있습니다.
[code]$(‘person-example’).request({
  method: ‘get’,
  parameters: { interests:’JavaScript’, ‘hobbies[]’:[‘programming’, ‘music’] },
  onComplete: function(){ alert(‘Form data saved!’) }
})[/code]

reset : 폼의 내용을 디폴트 값으로 초기화 합니다.
[code]reset(formElement) -> HTMLFormElement[/code]

예제)
[code]Form.reset(‘contact’);
// 다음과 동일


$(‘contact’).reset();
// 둘다 reset 버튼을 누른것과 동일한 효과를 가져옴[/code]

serialize : Ajax Request에 최적화된 문자열로 변환하거나 혹은 해시형 객체로 반환합니다.
[code]serialize(formElement[, getHash = false]) -> String | object[/code]

예제)
[code]$(‘person-example’).serialize();
// -> ‘username=sulien&age=22&hobbies=coding&hobbies=hiking’
$(‘person-example’).serialize(true);
// -> {username: ‘sulien’, age: ’22’, hobbies: [‘coding’, ‘hiking’]}[/code]

serializeElements : Form.serialize와 동일하나 특정 엘리먼트 배열을 인자로 받습니다.
[code]serializeElements(elements[, getHash = false]) -> string[/code]

예제)
[code]Form.serializeElements( $(‘myform’).getInputs(‘text’) )
// -> serialized data[/code]

Form.Element Methods ——————————————————————————————-
이 클래스는 폼 관련 메서드중에서도 폼안의 컨트롤 엘리먼트를 위한 메서드들을 모아놓은 클래스입니다.
Form과 많은 부분이 중복되니 새로운것만 써보도록 하겠습니다.

activate : 엘리먼트의 컨텐츠 영역에 커서가 이동하며 내용이 있었다면 해당 내용이 선택됩니다.
[code]activate(element) -> HTMLElement[/code]

예제)
[code]Form.Element.focus(‘myelement’).select();
$(‘myelement’).activate();[/code]

clear : text INPUT의 내용을 삭제합니다.
[code]clear(element) -> HTMLElement[/code]

예제)
[code]$(‘some_field’).onfocus = function() {
  // 이미 삭제되었다면 아무것도 하지 않음
  if(this._cleared) return
  // this키워드는 폼컨트롤 엘리먼트 자신을 지칭
  this.clear()
  this._cleared = true
} [/code]

disable : Form 클래스와 동일

enable : Form 클래스와 동일

focus : 해당 엘리먼트에 키보드 포커스를 줍니다.
[code]focus(element) -> HTMLElement[/code]

예제)
[code]Form.Element.focus(‘searchbox’);
// 위와 거의 동일. 하지만 아래는 JS native 메서드이기 때문에 엘리먼트를 반환하지 않음
$(‘searchbox’).focus();[/code]

getValue : 엘리먼트의 값을 가져옵니다. 간단하게 사용할 수 있는 유틸리티 함수인 $F()가 있습니다.
[code]getValue(element) -> string | array[/code]

예제)
[code]var form = $(‘contact’);
var input = form[‘company’];
Form.Element.getValue(input);


// 다음과 같은 방법도 있음
$(input).getValue();
// $()메서드는 확장된 엘리먼트를 가져올 수 있음
// 하지만 $F(input)을 사용하면 위의 과정을 더욱 단축 시킬 수 있음[/code]

present : 엘리먼트안의 값이 존재하는지를 확인합니다.
[code]present(element) -> boolean[/code]

예제)
[code]$(‘example’).onsubmit = function(){
  var valid, msg = $(‘msg’)
  // 두 필드의 prestion() 결과가 참인가?
  valid = $(this.username).present() && $(this.email).present()
  if (valid) {
    // 기본적인 처리를 한 후 return true 한다
    msg.update(‘Passed validation!’).style.color = ‘green’
  } else {
    msg.update(‘Please fill out all the fields.’).style.color = ‘red’
  }
  return false
}[/code]

select : 해당 폼컨트롤의 값 전체를 선택합니다.
[code]select(element) -> HTMLElement[/code]

예제)
[code]$(‘searchbox’).onfocus = function() {
  Form.Element.select(this);
  // 다음의 native 메서드를 사용할 수 있음. 하지만 엘리먼트를 반환하지 않음
  this.select();
}[/code]

serialize : Form 클래스와 동일

Exit mobile version