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="✓" /><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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With