问题
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!
回答1:
Ajax
In Rails, Ajax works exactly the same as anywhere else on the web - you send an asynchronous request with Javascript, server processes & sends a response.
The trick with Rails is to keep your code as modular as possible, hence why the ujs
stuff is so often used in apps. You'll be best reading up on Rails' ujs ajax capabilities here
As soon as the user selects it
Sounds like you need .on("change"
:
#app/assets/javascripts/application.js
$(document).on("change", function(){
$.ajax({
url: "your/path",
data: {search: $(this).val()},
success: function(data) {
// ... do stuff here
}
});
});
This will basically send the request to your server, allowing you to process the response as you wish.
Immediately take the building ID returned by the method and store it in a hidden field
You'll want to do this:
#Ajax method
success: function(data) {
$("#element").val(data);
}
This will need to be accompanied by the respond_to
block in your controller like this:
#app/controllers/your_controller.rb
respond_to :js, :json
def search
@search = Model.search params[:search]
respond_with @search
end
--
Data
Interesting point - you can use .find_by
instead of multiple where
queries like this:
Model.find_by(name: value, name: value).pluck(:id)
回答2:
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
回答3:
Here is an example related to this problem, hope this will be helpful to you. In this example we will validate the email.
Define a method in users_controller
and set the routes at routes.rb
class UsersController < ApplicationController
def check_email
@email = User.exists?(:email=> params[:email])
respond_to do |format|
if @email
format.json { render json: @email }
else
format.json { render json: @email }
end
end
end
routes.rb get "check_email" => "users#check_email"
Now come to the register.html.erb page and add javascript
as:
$('#email').blur(function(){
var re = /[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}/igm;
if($('#email').val().trim()=="" || !re.test($('#email').val()))
{
$("#lbl_email").text("*Please enter a valid email address");
$('#lbl_email').show();
return false;
}
else
{
$('#lbl_email').hide();
$.ajax({
type: "GET",
url: "/check_email",
data:{ email: $(this).val() },
dataType: "json",
success:function(data){
$('#lbl_email').show();
$("#lbl_email").text("*Oppss! Email already exists");
return false;
},
error: function() {
$('#lbl_email').hide();
}
});
}
});
来源:https://stackoverflow.com/questions/24073795/ujs-ajax-rails-4-form-for-collection-select-to-pass-value-into-method-and-ret