Skip to main content

How do I get redirect to view after create action using Vue.js

Javascript • Asked by Tabish Iqbal

Out of interest, have a weird issue. Trying to do a redirect after create. The record is being created just fine, but get a 500 error on the redirect? Using an ajax call using Vue-resource. Below is the code. (gist for better readability : https://gist.github.com/tabishiqbal/6c3839e53b5c5d34f0cbcc98185bb326)

CREATE METHOD IN CONTROLLER

def create
  @proposal = @project.proposals.create(proposal_params)
  authorize @proposal
  respond_to do |format|

    if @proposal.save!
      format.html { redirect_to project_proposal_path(@proposal.project, @proposal), notice: "Proposal successfully created and submitted to the client" }
      format.json { render :show, status: :created, location: @proposal }
      @project.update_attribute(:status_id, set_quote_ready)

      # As there is a new final, all previous versions are no longer current
      @project.proposals.where.not(id: @proposal.id).update_all(current: false)

      # Set this new final version as the current version
      if @project.proposals.all_final.count > 1
        @user.notify_user("#{@project.supplier.display_name} has updated their proposal. Check it out!", @project.id)
        @project.supplier.notify_business("Your revised proposal has been submitted to the client for approval", @project.id)
      else
        @user.notify_user("#{@project.supplier.display_name} has submitted a proposal for your project. Accept it to start the project", @project.id)
        @project.supplier.notify_business("Your proposal has been submitted to the client for approval", @project.id)
      end

      #UserMailer.new_proposal(@project.user).deliver_now
    else
      format.html { render :new, notice: "Proposal could not be saved" }
      format.json { render json: @proposal.errors, status: :unprocessable_entity }
    end
  end
end

SAVE METHOD IN VUE

saveProposal: function(final) {
    this.$validator.validateAll()

    if (!this.errors.any()) {

        this.saving = true

        if (final == true ) {

            this.proposal.final = true

        } else {

            this.proposal.final = false

        }

        for (var i = 0; i < proposal.milestones_attributes.length; i ++) {

            var ms = proposal.milestones_attributes[i]

            ms.dependencies_attributes = ms.dependencies
            console.log(ms)

        }

        this.$http.post('/projects/' + this.proposal.project_id + '/proposals', {
            proposal: proposal
        })

        .then(function (response) {
            console.log('Saved successfully')
            Turbolinks.visit('/projects/' + this.project.id + '/proposals/${response.body.id}')
        })

        .catch(error => {
            console.log('Error saving proposal. Please correct the errors')
            this.saving = false
        });

** VIEW**

<%= content_tag :div,
  id: "proposal-form",
  data: {
    project: @project.to_json(include: [:industry, :addons, :features, :budget, :type]),
    proposal: @proposal.to_json(except: [:created_at, :updated_at]),
    sections_attributes: @proposal.sections.to_json(except: [:proposal_id, :created_at, :updated_at]),
    cost_items_attributes: @proposal.cost_items.to_json(except: [:proposal_id, :created_at, :updated_at]),
    milestones_attributes: @proposal.milestones.to_json(except: [:proposal_id, :created_at, :updated_at], include: (:dependencies)),
    feedback: @feedback.to_json
  } do %>

<% end %>

PROPOSAL PARAMS

def proposal_params
    params
      .require(:proposal)
      .permit(
        :project_id,
        :supplier_id,
        :version,
        :final,
        :accepted,
        :accepted_at,
        :current,
        billing_phases: [],
        sections_attributes: [
          :id,
          :title,
          :body
        ],
        cost_items_attributes: [
          :id,
          :name,
          :category,
          :timing,
          :price,
          :quantity,
          :taxable,
          :tax,
          :gross,
          :net
        ],
        milestones_attributes: [
          :id,
          :name,
          :due_date,
          :done,
          dependencies_attributes: [
            :id,
            :name,
            :due_date,
            :done
          ]
        ]
      )
      .merge(
        project_id: @project.id,
        supplier_id: @project.supplier_id,
        user_id: @project.user.id,
        version: @version,
        current: true
      )

  end

Chris:
what is your json look like
it is trying to do a proposal_url but you don’t have a route for it?


Stephen

Hey @excid3 I’m doing a standard rails show view (not Json’d), but in terms of the JSON parsing, does this help?


PROPOSAL JSON

var project = JSON.parse(element.dataset.project)
      var proposal = JSON.parse(element.dataset.proposal)
      var sectionsAttributes = JSON.parse(element.dataset.sectionsAttributes)
      var costItemsAttributes = JSON.parse(element.dataset.costItemsAttributes)
      var milestonesAttributes = JSON.parse(element.dataset.milestonesAttributes)
      var feedback = JSON.parse(element.dataset.feedback)

      proposal.sections_attributes = sectionsAttributes
      proposal.cost_items_attributes = costItemsAttributes
      proposal.milestones_attributes = milestonesAttributes

Chris

you’re submitting the form with Vue-resource / axios
and it wants JSON back
you should see the request in rails say “as JSON”
right?


Stephen

wait a sec, are you referring to this:
format.json { render :show, status: :created, location: @proposal } in the proposal create action?


Chris

you should do
format.json { render json: @proposal }

think of it this way
Javascript submits the form to Rails
JS tells it that it wasnt JSON in return
so Rails says okay cool, and calls the format.json block
it needs to render JSON to send back so the Javascript can parse it
and then the JS can redirect using Turbolinks.visit()
you have to include a url of some sort in the JSON back so it can know where to go

one simple thing is to do like
format.json { render json: @proposal, location: @proposal } (edited)
the location will set a url in the HTTP location header you can use to redirect
and still give you the json data of the proposal
but your error from rails said there was no resources :proposals in your routes
so it can’t make that url
you’ll have to fix that or change the url


Stephen

Ahhh, ok cool. Can you do nested resources with the JSON response? So at the moment, I wanted to redirect to something like /projects/121/proposals/24

Or do I need to create an unnested route for the proposal show action?


Chris

just pass the url into location
format.json { render json: @proposal, location: [@project, @proposal] } will probably work too


Chris

I haven’t actually used the location header with vue-resource so you may have to access it some different way
or you can put it into the json
nevermind, looks easy: Turbolinks.visit(response.headers.get('Location'));


Stephen

Omg, that worked!
Thats brilliant.

Chris you're awesome. I love you man. (his real words / feelings)


Haha, thats exactly how I felt :) Thanks again @excid3


LOL this is great. Slack regurgitation to the forum.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 22,346+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.