msadoon msadoon - 3 months ago 16
Ajax Question

UJS, AJAX, Rails 4, form_for collection_select to pass value into method and return value back to form

I'm very new to Rails, and as such am having lots of of confusion when dealing with AJAX, UJS and Rails together. I've looked at railscast, several SO answers, tried #rubyonrails IRC channel on freenode.
Alas, I'm still stuck.

Anyway, here is my problem.

SO I have two Models, Building and Property. Property belongs_to Building and Building has_many Properties.

I've added the foreign key to Property as building_id.

Now, in my building model, I have a Method: self.search(search) and given the right address (example 999 Decarie), it will return the building_id from Building table in the database correctly.

def self.search(search)
#search.instance_variables.map {|v| "#{v}: #{search.instance_variable_get(v)}\n"}.join
if ((search.nil?) || (search == ""))
nil
else
search = search.to_s
d { search }
split = search.split(' ', 2)
stnum = split.first
d { stnum }
stname = split.last
d { stname }
Building.where("streetno = ?", stnum).where("streetname = ?", stname).pluck(:id).first
end
end


In my Properties partial _form, I have a form_for loop that uses a collection_select to allow the users to pick any building address (ex. 999 Decarie), (so it renders as a select/option HTML drop-down list).

<div class="field" id="selection">
<%= f.collection_select :buildinginfo, Building.all, :half_address, :half_address, {:label => "Building Info"}%>
</div>


So, how do I, using unobtrusive javascript/ajax

A. Get the selected value of the collection select as soon as the user selects it in the form and pass it to the building model method mentioned above (self.search(search)), which returns the correct building ID.

B. immediately take the building ID returned by the method and store it in a hidden field on the form (which corresponds to building_id field in the Properties model). (in the code below I want replace the value 1 with the building ID)

<div class="field" id="selection_id">
<%= f.hidden_field :building_id, :value => 1 %>
</div>


Thus, allowing my associations to work such that when I delete a building, all its related properties get deleted as well.

Let me know if you need more code, im using Rails 4, thank you so much!

Answer

thanks for taking the time to explain this Rich.

While your approach makes sense, I used a different approach, because my end goal was simply to create associations between Building (has_many) and Property (belongs_to), and when I delete a Building I also want all Properties associated to it deleted as well.

So when creating/updating a property I need to add it to the Building.properties array, which automatically updates the property's building_id field.

here's my final code in the properties_controller:

def create
  @property = Property.new(property_params)

  **b_id = Building.search(@property.buildinginfo)**
  **Building.find_by(id: b_id).properties << @property**

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

def update
respond_to do |format|
  if @property.update(property_params)

    **b_id = Building.search(@property.buildinginfo)**
    **Building.find_by(id: b_id).properties << @property**

    format.html { redirect_to @property, notice: 'Property was successfully updated.' }
    format.json { render :show, status: :ok, location: @property }
  else
    format.html { render :edit }
    format.json { render json: @property.errors, status: :unprocessable_entity }
  end
end
end

The Building.search function (goes in the building Model):

    def self.search(search)

    if ((search.nil?) || (search == ""))
        nil
    else
        search = search.to_s
        split = search.split(' ', 2)
        stnum = split.first
        stname = split.last
        s = Building.where("streetno = ?", stnum).where("streetname = ?",  stname).pluck(:id).first
        s
    end
end