Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(How) Can I use a form object for the edit/update routines?

Couldn't resist to try out the relaunched RailsForum and crossposted this question here.

I have the following form object (in Rails 4)

class StationForm
    include Virtus

    include ActiveModel::Model
    # I think this is unnecessary
    #   extend ActiveModel::Naming
    #   include ActiveModel::Conversion
    #   include ActiveModel::Validations


# Station
    attr_reader :station

    attribute :station_name, String
    attribute :station_description, String

# Address
    attr_reader :address

    attribute :address_url, String
    attribute :address_priority, Integer
    attribute :address_is_active, Boolean

    def persisted?
        false
    end

    def save
        if valid?
            persist
            true
        else
            false
        end
    end

private

    def persist
        @station = Station.create(name: station_name, description: station_description)
        @address = @station.addresses.create(url: address_url, priority: address_priority, is_active: address_is_active)
    end
end

I can use this form object in my new/create methods

class StationsController < ApplicationController
    def new
        @station_form = StationForm.new
    end

    def create
        @station_form = StationForm.new(station_form_params)
        @station_form.save

        redirect_to station_path(@station)
    end

private

    def station_form_params
        params.require(:station_form).permit(:station_name, :station_description, :address_url, :address_priority, :address_is_active)
    end
end

However, I don't succeed to use it for the edit/update procedures...

Is it possible to use the form object for edit/update and if yes, how would this be done?

like image 848
speendo Avatar asked Oct 04 '22 03:10

speendo


1 Answers

You will have to use "initialize" method in StationForm object to use it for editing. if you pass an id, it will assume, that the object already exist and from there we can treat it as an persisted object. Also Add "update" method to update attributes of object.

class StationForm
include Virtus.model

include ActiveModel::Model
# I think this is unnecessary
#   extend ActiveModel::Naming
#   include ActiveModel::Conversion
#   include ActiveModel::Validations


attr_reader :station

attribute :station_name, String
attribute :station_description, String

attr_reader :address

attribute :address_url, String
attribute :address_priority, Integer
attribute :address_is_active, Boolean

def initialize(attr = {})
 if !attr["id"].nil?
    @station = Station.find(attr["id"])
    @address = @station.addresses.first
    self[:station_name] = attr[:station_name].nil? ? @station.name : attr[:station_name]
    self[:station_description] = attr[:station_description].nil? ? @station.description : attr[:station_description]
    self[:address_url] =  attr[:address_url].nil? ? @address.url : attr[:address_url]
    self[:address_priority] = attr[:address_priority].nil? ? @address.priority : attr[:address_priority]
    self[:address_is_active] = attr[:address_is_active].nil? ? @address.is_active : attr[:address_is_active]
 else
   super(attr)
 end
end

def persisted?
    @station.nil? ? false : @station.persisted?
end

def id
   @station.nil? ? nil : @station.id
end

def save
    if valid?
        persist
        true
    else
        false
    end
end

def update
    if valid?
        update_form
        true
    else
        false
    end
end

private

 def persist
    @station = Station.create(name: station_name, description: station_description)
    @address = @station.addresses.create(url: address_url, priority: address_priority, is_active: address_is_active)
 end

 def update_form
    @station.update_attributes(
        :name => self[:station_name],
        :description => self[:station_description]
        )
    @address.update_attributes(
        :url => self[:address_url],
        :priority => self[:address_priority],
        :is_active=> self[:address_is_active]
        )
 end
end

And Controller will be like

def new
 @station = StationForm.new
end

def edit
 @station = StationForm.new("id" => params[:id])
end

def create
  @station = StationForm.new(station_params)

 respond_to do |format|
   if @station.save
     format.html { redirect_to  stations_path, notice: 'Station was  successfully created.' }
     format.json { render :show, status: :created, location: @station }
   else
     format.html { render :new }
     format.json { render json: @station.errors, status: :unprocessable_entity  }
    end
 end
end

def update
 @station = StationForm.new(station_params.merge("id" => params[:id]))
 respond_to do |format|
   if @station.update
     format.html { redirect_to stations_path, notice: 'Station was  successfully updated.' }
     format.json { render :show, status: :ok, location: @station }
   else
     format.html { render :edit }
     format.json { render json: @station.errors, status: :unprocessable_entity  }
   end
 end
end

use the "persisted" and "id" method from StationForm in the _form.html.erb

    <%= form_for(@station,
:url => @station.persisted? ? station_path(@station.id) : stations_path,
:method => @station.persisted? ? "put": "post") do |f| %>
  <% if @station.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@station.errors.count, "error") %> prohibited this station from being saved:</h2>

      <ul>
      <% @station.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :station_name %><br>
    <%= f.text_field :station_name %>
  </div>
  <div class="field">
    <%= f.label :station_description %><br>
    <%= f.text_field :station_description %>
  </div>
  <div class="field">
    <%= f.label :address_url%><br>
    <%= f.text_field :address_url %>
  </div>
  <div class="field">
    <%= f.label :address_priority%><br>
    <%= f.text_field :address_priority%>
  </div>
  <div class="field">
    <%= f.label :address_is_active %><br>
    <%= f.text_field :address_is_active %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
like image 77
Atul Avatar answered Oct 12 '22 12:10

Atul