form_for without ActiveRecord, form action not updating
Asked Answered
P

3

9

I'm using an API instead of a database, so I'm not using ActiveRecord but ActiveModel (I mostly did like here: railscasts.com/episodes/219-active-model)

Thing is, when I try to edit an item (in my case a parking), the action of the form still remains the action of the create and not update.

so when I go on /parkings/2/edit to edit a parking, the form is still:

<form accept-charset="UTF-8" action="/parkings" class="form-horizontal" id="new_parking" method="post">

when it should be more like that with the put hidden field and the parkings/2 as the action:

<form accept-charset="UTF-8" action="/parkings/2" class="form-horizontal" id="edit_parking" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="_method" type="hidden" value="put" />

Anybody knows where the method & action of the form_for is set according to the route? What I'm trying to do is be as close as if I was using ActiveRecord with a database.

Here is some code :

_form.html.erb

<%= form_for(@parking, :html => { :class => "form-horizontal" }) do |f| %>
...
<% end %>

edit.html.erb & new.html.erb, simply has

<%= render 'form' %>

Controller

class ParkingsController < ApplicationController
  def index    
    @parkings = Parse.get("Parking")

    respond_to do |format|
      format.html
      format.json { render :json => @parking }
    end
  end

  def new
    @parking = Parking.new

    respond_to do |format|
      format.html
      format.json { render :json => @parking }
    end
  end

  def edit
    @parking = Parking.find(params[:id])

    respond_to do |format|
      format.html
      format.json { render :json => @parking }
    end
  end

  def create
    @parking = Parking.new(params[:parking])
    if (@parking.save)
       flash[:success] = "Parking was just added!"
       redirect_to :action => "new"
    else
      render :action => "new"
    end
  end

  def update
   # Testing
   parking = Parse.get("Parking", params[:id])
   parking.delete("updatedAt")
   parking["name"] = params[:parking][:name]
   parking.save

   redirect_to :action => "index"
  end

Model

class Parking
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming

  attr_accessor :name, :address, :city, :longitude, :latitude, :contributor_name, :contributor_email
  validates_presence_of :name, :address, :city, :longitude, :latitude

  @id = nil

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def self.find(id)
    @id = id
    raw                       = Parse.get("Parking", @id.to_s)

    parking = Parking.new
    parking.name              = raw["name"]
    parking.address           = raw["address"]
    parking.city              = raw["city"]
    parking.longitude         = raw["location"]["longitude"]
    parking.latitude          = raw["location"]["latitude"]
    parking.contributor_name  = raw["contributorName"]
    parking.contributor_email = raw["contributorEmail"]

    return parking
  end

  def save
    if (!valid?)
      return false
    else
      parking = Parse::Object.new("Parking")

      data =
      {
        :longitude => longitude.to_f,
        :latitude  => latitude.to_f
      }

      point = Parse::GeoPoint.new(data)

      parking["location"]         = point
      parking["name"]             = name
      parking["address"]          = address
      parking["city"]             = city
      parking["contributorName"]  = contributor_name
      parking["contributorEmail"] = contributor_email

      if (parking.save)
        return true
      end
    end
  end

  def persisted?
    false
  end
end

Please note that the create is working and if I add the id of my parking in the form action="" using the Web Inspector or Firebug, and add :method => "put" in my form_for, my record successfully update.

The real problem here is really the form_for action & method who doesn't get updated when I'm editing a parking and remains like if I was adding a new one.

I'm still learning Rails, so sorry if some infos aren't clear!

Thank you!

--- SOLUTION ---

persisted? shouldn't only return false, and my model needed to define a method that returns the id of the object (so they can update the action="") so here's is my updated model:

class Parking
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming

  attr_accessor :objectId, :name, :address, :city, :longitude, :latitude, :contributor_name, :contributor_email
  validates_presence_of :name, :address, :city, :longitude, :latitude

  @id = nil

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def self.find(id)
    raw                       = Parse.get("Parking", id.to_s)

    parking = Parking.new
    parking.objectId          = id
    parking.name              = raw["name"]
    parking.address           = raw["address"]
    parking.city              = raw["city"]
    parking.longitude         = raw["location"]["longitude"]
    parking.latitude          = raw["location"]["latitude"]
    parking.contributor_name  = raw["contributorName"]
    parking.contributor_email = raw["contributorEmail"]

    return parking
  end

  def save
    if (!valid?)
      return false
    else
      parking = Parse::Object.new("Parking")

      data =
      {
        :longitude => longitude.to_f,
        :latitude  => latitude.to_f
      }

      point = Parse::GeoPoint.new(data)

      parking["location"]         = point
      parking["name"]             = name
      parking["address"]          = address
      parking["city"]             = city
      parking["contributorName"]  = contributor_name
      parking["contributorEmail"] = contributor_email

      if (parking.save)
        return true
      end
    end
  end

  def update_attributes(aParking)
    parking = Parse.get("Parking", @id.to_s)
    parking.delete("updatedAt")

    parking["name"] = aParking["name"]
    parking.save

    return true
  end

  def destroy
    parking = Parse.get("Parking", @id)
    #parking.parse_delete
  end

  def id
    return self.objectId
  end

  def persisted?
    !(self.id.nil?)
  end
end
Pliocene answered 6/3, 2012 at 4:38 Comment(0)
F
6

I think your problem is in your model's persisted? method. Since it always returns false, Rails always thinks it's building a form for a newly created record, so it uses POST and submits to the collection URL.

You need some sort of logic in that method so that existing records return true and new records return false.

Falsework answered 6/3, 2012 at 5:26 Comment(4)
Would you have any idea of that logic or hints?Pliocene
I really can't help much more than to hazard a guess. Judging from your controller logic, it looks like a "fresh" Parking object won't have any of its attributes set. Perhaps your persisted? method could simply check for the existence of one or more of those attributes. It's application-specific, so it's up to you to figure out what it means.Falsework
You may also need to set the id of the new object.Airman
You were right! I just had to define a method id that returns the id of my object and that's it! I'll update my question!Pliocene
S
1

Hi friend you can to tell the form builder which method to use.So try

<%= form_for(@parking, :method => ["new", "create"].include?(action_name) ? :post : :put,
    :html => { :class => "form-horizontal" }) do |f| %>
  ...
 <% end %>
Spunky answered 6/3, 2012 at 6:6 Comment(0)
C
-1

If you are not using ActiveRecord you should use 'form_tag' instead 'form_for'

Certifiable answered 6/3, 2012 at 8:35 Comment(2)
Why? ActiveModel is made for that no? Take a look at the railscast, they also use te form_for tagPliocene
Sorry, my mistake, I haven't see that you was using ActiveModel, thought was a form without ActiveModel and ActiveRecord.Certifiable

© 2022 - 2024 — McMap. All rights reserved.