Rails 3 : Ajax 호출에서 "redirect_to"하는 방법?


85

attempt_login로그인 양식을 제출 한 후 Ajax를 사용하여 다음 메소드를 호출합니다.

class AccessController < ApplicationController
  [...]
  def attempt_login
    authorized_user = User.authenticate(params[:username], params[:password])

    if authorized_user
      session[:user_id] = authorized_user.id
      session[:username] = authorized_user.username
      flash[:notice] = "Hello #{authorized_user.name}."
      redirect_to(:controller => 'jobs', :action => 'index')
    else
      [...]
    end
  end
end

문제는 redirect_to작동하지 않는다는 것입니다.

이 문제를 어떻게 해결 하시겠습니까?

답변:


102

마지막으로

redirect_to(:controller => 'jobs', :action => 'index')

이것으로 :

render :js => "window.location = '/jobs/index'"

잘 작동합니다!


43
더 좋은 방법이 될 것이다render :js => "window.location = '#{jobs_path}'"
zakelfassi

3
작동하지만 실제 json 성공 메시지와 함께 리디렉션 위치를 다시 전달하고 프런트 엔드에서 리디렉션을 수행하는 것이 훨씬 낫지 않습니까?
justinxreese 2014-06-06

1
jobs_path기본적으로 URL만큼 엄격 하지 않습니까? URL이 변경되면 특별히주의하지 않는 한 경로 이름도 변경됩니다. 또 다른 대안은 render js: "window.location = '#{polymorphic_path(@job.class)}'"작업 모델을 기반으로 계산 된 리소스가 풍부한 경로를 사용하는 것 입니다. 이것은 경로가 풍부하고 모델과 일치하는 표준 명명 규칙을 사용하는 경우에만 작동합니다. (또는 올바른 경로 이름을 생성하도록 모델에 model_name을 지정하는 경우)
smudge

2
대박. 누구나 간단한 redirect_to가 작동하지 않는 이유를 알고 있습니까?
Tasos Anesiadis 2016

1
@Tasos Anesiadis, redirect_to는 양식이 '원격'Rails 양식 인 경우 작동하지 않습니다. 브라우저가 컨트롤러의 응답을 자바 스크립트로 해석하도록 지시했기 때문입니다. Chrome DevTools의 응답 탭 (네트워크 패널을 통해)에서 redirect_to 페이지를 볼 수 있지만 대신 컨트롤러에서 다른 페이지를 찾기 위해 브라우저에 지시하는 것이 필요합니다. 여기에 제공된 window.location 솔루션 또는 fetch () 및 JSON을 통해 양식 데이터를 수동으로 제출하고 처리하려는 경우가 아니라면 양식을 일반 '로컬'양식으로 변경해야합니다.
MSC

67

다음 요청을 위해 플래시를 유지하는 매우 쉬운 방법이 있습니다. 컨트롤러에서 다음과 같이하십시오.

flash[:notice] = 'Your work was awesome! A unicorn is born!'
flash.keep(:notice)
render js: "window.location = '#{root_path}'"

flash.keep반드시 플래시가 다음 요청을 유지하게됩니다. 따라서이 root_path렌더링되면 주어진 플래시 메시지가 표시됩니다. Rails는 굉장합니다 :)


28

나는 이것이 약간 더 좋다고 생각합니다.

render js: "window.location.pathname='#{jobs_path}'"


12
: 약간 약간 더 좋은render js: "window.location.pathname = #{jobs_path.to_json}"
tokland

26

내 앱 중 하나에서 JSON을 사용하여 리디렉션 및 플래시 메시지 데이터를 수행합니다. 다음과 같이 보일 것입니다.

class AccessController < ApplicationController
  ...
  def attempt_login
    ...
    if authorized_user
      if request.xhr?
        render :json => {
          :location => url_for(:controller => 'jobs', :action => 'index'),
          :flash => {:notice => "Hello #{authorized_user.name}."}
        }
      else
        redirect_to(:controller => 'jobs', :action => 'index')
      end
    else
      # Render login screen with 422 error code
      render :login, :status => :unprocessable_entity
    end
  end
end

그리고 간단한 jQuery 예제는 다음과 같습니다.

$.ajax({
  ...
  type: 'json',
  success: functon(data) {
    data = $.parseJSON(data);
    if (data.location) {
      window.location.href = data.location;
    }
    if (data.flash && data.flash.notice) {
      // Maybe display flash message, etc.
    }
  },
  error: function() {
    // If login fails, sending 422 error code sends you here.
  }
})

1
여기에 좋은 정보가 많이 있습니다. render : location, : status 옵션 및 xhr의 적절하고 적절한 사용? 검사. 더 많은 웹 애플리케이션이 모바일 앱 등을 제공하기 위해 API를 채택함에 따라이 게시물의 내용이 더 표준화되기를 바랍니다. 확실히 내 찬성 투표를 해. 멋진 대답
TheJKFever

18

모든 답변의 최고 조합 :

...
if request.xhr?
  flash[:notice] = "Hello #{authorized_user.name}."
  flash.keep(:notice) # Keep flash notice around for the redirect.
  render :js => "window.location = #{jobs_path.to_json}"
else
...

답변 해 주셔서 감사합니다. 사용했습니다. 그러나 이제 테스트를 위해이 작업을 JS로 요청하려고하면 CORS 경고가 발생합니다. ActionController :: InvalidCrossOriginRequest. 이것을 테스트에 통합하는 방법에 대해 알고 있습니까?
V. Déhaye

1
def redirect_to(options = {}, response_status = {})
  super(options, response_status)
  if request.xhr?
    # empty to prevent render duplication exception
    self.status = nil
    self.response_body = nil
    path = location
    self.location = nil

    render :js => "window.location = #{path.to_json}"
  end
end

0

컨트롤러 동작을 수정하고 싶지 않았기 때문에이 해킹을 생각해 냈습니다.

class ApplicationController < ActionController::Base
  def redirect_to options = {}, response_status = {}
    super

    if request.xhr?
      self.status        = 200
      self.response_body = "<html><body><script>window.location.replace('#{location}')</script></body></html>"
    end
  end
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.