How to Include 2 Models in 1 Form? - javascript

One model creates :name, :metric (Quantified.rb), and the other creates :result_value, :result_date (Result.rb).
class Quantified < ActiveRecord::Base
belongs_to :user
scope :averaged, -> { where(categories: 'Monthly Average') }
scope :instance, -> { where(categories: 'One-Time Instance') }
has_many :results
CATEGORIES = ['Monthly Average', 'One-Time Instance']
end
class Result < ActiveRecord::Base
belongs_to :user
belongs_to :quantified
end
What do I need to do in the _form and/or controller that would allow a User to add his results_date & results_value (results _form) to a respective name and metric (quantifieds _form)?
<%= form_for(#quantified) do |f| %>
<% if #quantified.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quantified.errors.count, "error") %> prohibited this quantified from being saved:</h2>
<ul>
<% #quantified.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="america">
<form>
<%= f.select :categories, Quantified::CATEGORIES %>
<br>
<br>
<div class="form-group">
<%= f.text_field :name, class: 'form-control', placeholder: 'Enter Name' %>
</div>
<div class="form-group">
<%= f.text_field :metric, class: 'form-control', placeholder: 'Enter Metric (i.e. Miles, Pounds, $, Subscribers)' %>
</div>
<div class="date-group">
<label> Date: </label>
<%= f.date_select :date, :order => [:month, :year], class: 'date-select' %>
</div>
<div class="america2">
<%= button_tag(type: 'submit', class: "btn") do %>
<span class="glyphicon glyphicon-plus"></span>
<% end %>
<%= link_to quantifieds_path, class: 'btn' do %>
<span class="glyphicon glyphicon-chevron-left"></span>
<% end %>
<%= link_to #quantified, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn' do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
</form>
</div>
<% end %>
<%= form_for(#result) do |f| %>
<% if #result.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#result.errors.count, "error") %> prohibited this result from being saved:</h2>
<ul>
<% #result.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="america">
<form>
<div class="form-group">
<%= f.text_field :result_value, class: 'form-control', placeholder: 'Enter Result' %>
</div>
<div class="date-group">
<label> Date: </label>
<%= f.date_select :result_date, :order => [:month, :year], class: 'date-select' %>
</div>
<div class="america2">
<%= button_tag(type: 'submit', class: "btn") do %>
<span class="glyphicon glyphicon-plus"></span>
<% end %>
<%= link_to results_path, class: 'btn' do %>
<span class="glyphicon glyphicon-chevron-left"></span>
<% end %>
<%= link_to #result, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn' do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
</form>
</div>
<% end %>
For example User inputs:
:name = Ran
:metric = miles
Then for every month henceforth he would input his average miles ran for that month. How do I create a relationship between these two forms?
:result_value = 2.1
:result_date = January
:result_value = 1.8
:result_date = December
*Each name/metric has many result values/dates.
controllers
class QuantifiedsController < ApplicationController
before_action :set_quantified, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#results = Result.all.order("result_date")
end
def show
end
def new
#quantified = current_user.quantifieds.build
end
def edit
end
def create
#quantified = current_user.quantifieds.build(quantified_params)
if #quantified.save
redirect_to quantifieds_url, notice: 'Goal was successfully created'
else
render action: 'new'
end
end
def update
if #quantified.update(quantified_params)
redirect_to quantifieds_url, notice: 'Goal was successfully updated'
else
render action: 'edit'
end
end
def destroy
#quantified.destroy
redirect_to quantifieds_url
end
private
def set_quantified
#quantified = Quantified.find(params[:id])
end
def correct_user
#quantified = current_user.quantifieds.find_by(id: params[:id])
redirect_to quantifieds_path, notice: "Not authorized to edit this goal" if #quantified.nil?
end
def quantified_params
params.require(:quantified).permit(:categories, :name, :metric, :result, :date)
end
end
class ResultsController < ApplicationController
before_action :set_result, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#results = Result.all.order("result_date")
end
def show
end
def new
#result = current_user.results.build
end
def edit
end
def create
#result = current_user.results.build(result_params)
if #result.save
redirect_to #result, notice: 'Goal was successfully created'
else
render action: 'new'
end
end
def update
if #result.update(result_params)
redirect_to #result, notice: 'Goal was successfully updated'
else
render action: 'edit'
end
end
def destroy
#result.destroy
redirect_to results_url
end
private
def set_result
#result = Result.find(params[:id])
end
def correct_user
#result = current_user.results.find_by(id: params[:id])
redirect_to results_path, notice: "Not authorized to edit this result" if #result.nil?
end
def result_params
params.require(:result).permit(:result_value, :result_date)
end
end
The index would turn something out like this where each name (metric)'s would have multiple results and dates:
I tried implementing these instructions but I keep getting different errors with different variations: http://archive.railsforum.com/viewtopic.php?id=717
I also tried this tutorial: http://railscasts.com/episodes/197-nested-model-form-part-2. But it's a bit outdated so I get a bunch of errors.
Thanks in advance for any help you could give me!

what you are trying to do is NestedAttributes you can read more about it http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Examples:
# creates avatar_attributes=
accepts_nested_attributes_for :avatar, reject_if: proc { |attributes| attributes['name'].blank? }
# creates avatar_attributes=
accepts_nested_attributes_for :avatar, reject_if: :all_blank
# creates avatar_attributes= and posts_attributes=
accepts_nested_attributes_for :avatar, :posts, allow_destroy: true
this is the class definition
# File activerecord/lib/active_record/nested_attributes.rb, line 301
def accepts_nested_attributes_for(*attr_names)
options = { :allow_destroy => false, :update_only => false }
options.update(attr_names.extract_options!)
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
attr_names.each do |association_name|
if reflection = _reflect_on_association(association_name)
reflection.autosave = true
add_autosave_association_callbacks(reflection)
nested_attributes_options = self.nested_attributes_options.dup
nested_attributes_options[association_name.to_sym] = options
self.nested_attributes_options = nested_attributes_options
type = (reflection.collection? ? :collection : :one_to_one)
generate_association_writer(association_name, type)
else
raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
end
end
end
Also if you need more there is a really cool video from rails cast that explains it http://railscasts.com/episodes/196-nested-model-form-part-1

Related

Replacing partial with AJAX in Rails 4: undefined method `id`

When replacing a partial through Ajax, one method is giving me the proper result but the other (almost identical) isn't. I want to select and deselect a group for a specific campaign. Selecting gives me a direct replacement, deselecting doesn't.
models/general_connection.rb
belongs_to :campaign
belongs_to :group
models/group.rb
has_many :general_connections
has_many :campaigns, through: :general_connections
models/campaign.rb
has_many :general_connections
has_many :groups, through: :general_connections
controllers/general_connection.rb
def connect_group_to_campaign
#group = Group.find(params[:group_id])
#campaign = Campaign.find(params[:campaign_id])
#campaign.general_connections.create(group: #group)
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
def disconnect_group_from_campaign
#general_connection = GeneralConnection.where("group_id = ? AND campaign_id = ?", params[:group_id], params[:campaign_id]).first
#group = #general_connection.group
#general_connection.destroy
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
views/campaign/show.html.erb
<div class="row">
<% #main_groups.each do |group| %>
<%= render partial: 'groups_form', locals: { group: group } %>
<% end %>
</div>
*views/campaign/_groups_form.html.erb
<div class="row" id="group_<%= group.id %>">
<div class="col m6">
<div class="valign-wrapper black-text">
<% if group.icon.nil? %>
<i class="material-icons">group</i>
<% else %>
<i class="material-icons"><%= group.icon %></i>
<% end %>
&nbsp<%= group.title %>
</div>
</div>
<div class="col m6">
<% if !grouped(group) %>
<%= form_tag connect_group_to_campaign_path(:group_id => group.id, :campaign_id => #campaign.id), remote: true do %>
<%= button_tag 'check_box_outline_blank', class: "secondary-content material-icons grey-text", style: "background-color:white;border:none;" %>
<% end %>
<% else %>
<%= form_tag disconnect_group_from_campaign_path(:group_id => group.id, :campaign_id => #campaign.id), remote: true do %>
<%= button_tag 'check_box', class: "secondary-content material-icons grey-text", style: "background-color:white;border:none;" %>
<% end %>
<% end %>
</div>
</div>
views/general_connection/connect_group_to_campaign.js.erb
$('#group_<%= #group.id %>').replaceWith('<%= j render partial: 'campaigns/groups_form', locals: {group: #group} %>');
views/general_connection/disconnect_group_from_campaign.js.erb
$('#group_<%= #group.id %>').replaceWith('<%= j render partial: 'campaigns/groups_form', locals: {group: #group} %>');
...and this is the error that I'm getting:
ActionView::Template::Error (undefined method `id' for nil:NilClass):
12: </div>
13: <div class="col m6">
14: <% if !grouped(group) %>
15: <%= form_tag connect_group_to_campaign_path(:group_id => group.id, :campaign_id => #campaign.id), remote: true do %>
16: <%= button_tag 'check_box_outline_blank', class: "secondary-content material-icons grey-text", style: "background-color:white;border:none;" %>
17: <% end %>
18: <% else %>
To sum it up: both methods are working, but only connect_group_to_campaign gives a direct result and disconnect_group_from_campaign doesn't and needs a browser refresh.
Can anyone help me out?
It seems #campaign object is not declared in disconnect_group_from_campaign method. Try it after adding the below line in your disconnect_group_from_campaign method
#campaign = Campaign.find(params[:campaign_id])

ajax call not updating content on rails

Im trying to implement a bit a Ajax into my app seems to work correctly but it isnt updating the page after the action is executed .
I added Ajax to my Destroy method
def destroy
#item = Item.find(params[:id])
#item.user = current_user
if #item.destroy
flash[:notice] = "Item Completed"
else
flash[:alert] = "Item was unable to be marked completed "
end
respond_to do |format|
format.html
format.js
end
end
i have update my _item.html.erb and _form.html.erb partials with remote: true
<%= content_tag :div, class: 'media', id: "item-#{item.id}" do %>
<div class="media">
<div class="media-body">
<small>
<%= item.name.titleize %>
| submitted <%= time_ago_in_words(item.created_at) %>
<% if current_user == #user %>
<%= link_to "Completed ", [#user, item], method: :delete,remote: true, class: 'glyphicon glyphicon-ok' %><br>
<% end %>
</small>
</div>
</div>
<% end %>
_from.html.erb
<%= form_for [#user, item ], remote: true do |f|%>
<div class="form-group">
<%= f.label :name, class: 'sr-only' %>
<%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
</div>
<%= f.submit "Submit Item", class: 'btn btn-primary pull-right' %>
<% end %>
User#show view <div class='new_item'>
<%= render :partial => 'items/form', :locals =>{:item => Item.new} %>
</div>
<% end %>
<div class='js-items'>
<% #user.items.order('created_at DESC').each do |item| %>
<%= render :partial => 'items/item' , :locals => {:item => item } %>
</div>
destroy.js.erb
$('#item-<%= #item.id %>').hide();
Like I said before, the item is deleted when i click the delete button but i need to refresh the page in order to see the updated page. Any ideas what i might be doing wrong, any push to the right direction would be greatly appreciated!
Try rendering the java script in the method itself and check,
def destroy
#item = Item.find(params[:id])
#item.user = current_user
if #item.destroy
flash[:notice] = "Item Completed"
else
flash[:alert] = "Item was unable to be marked completed "
end
respond_to do |format|
format.html
format.js { render
$('#item-<%= #item.id %>').hide();
}
end
end

Rails & Zurb Modal Loads Entire Page On Edit

I'm trying to edit content from my rails app Products through a zurb foundation modal. I can add new just fine. But when trying click the edit button, it loads a modal with the whole page again. Although it loads the correct edit page, I just want an edit form. Not a whole new render of my site.
Products_controller.rb
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
#product = Product.new
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
#product = Product.find(params[:id])
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :price)
end
end
index.html.erb
<h1>Listing products</h1>
Click Me For A Modal
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #products.each do |product| %>
<tr>
<td><%= product.name %></td>
<td><%= product.price %></td>
<td><%= link_to 'Show', product %></td>
<td><%= link_to 'Edit', edit_product_path(product) %></td>
<td><%= link_to 'EditM', edit_product_path(product), :remote => true, class: "", "data-reveal-id" => "editModal", "data-reveal-ajax" => edit_product_path(product) %></td>
<td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Product', new_product_path, class: "button radius", "data-reveal-id" => "addModal" %>
<div id="addModal" class="reveal-modal" data-reveal>
<%= render :partial => 'form', locals: { product: #products } %>
<a class="close-reveal-modal">×</a>
</div>
<div id="editModal" class="reveal-modal" data-reveal>
<%= render :partial => 'form' %>
<a class="close-reveal-modal">×</a>
</div>
_form.html.erb
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row">
<div class="small-3 columns">
<%= f.label :name, class: "right inline" %>
</div>
<div class="small-9 columns">
<%= f.text_field :name %>
</div>
</div>
<div class="row">
<div class="small-3 columns">
<%= f.label :price, class: "right inline", title: "Price In USD", data: { tooltip: true } %>
</div>
<div class="small-9 columns">
<%= f.text_field :price %>
</div>
</div>
<div class="row">
<div class="small-9 small-offset-3 columns">
<%= f.submit %>
</div>
</div>
<% end %>
Below is an image of how it loads after you select the EditM button.
I have updated my :edit method to the following. It appears to be working so it loads the action only, not the layout. Is this the proper way? Or should I be doing it differently?
def edit
#product = Product.find(params[:id])
render :layout => false
end
This is the modal in index.html.erb:
<div id="editModal" class="reveal-modal" data-reveal>
<a class="close-reveal-modal">×</a>
</div>

has_many and accepts_nested_attributes_for with nested forms and jquery/ajax

I'm trying to create a nested form where there is a "+" button which adds fields via jquery and ajax. I am doing it adding a step at once, so untill now I am able to add a simple text pushing the "+" button, but, as I have just said, I want to add some fields.
I have the followings:
new.html.erb
<h1>New Campaign</h1>
<%= form_for #campaign, html: { multipart: true } do |f| %>
....
<div class="goods">
<%= render "goods/good", f: f, child_index: Time.now.to_i %>
</div>
<div class="actions">
<%= link_to '+', add_good_row_path(params[:campaign]=#campaign, params[:f] = f), remote: true, class: 'btn btn-large btn-success' %>
<%= f.submit 'Crea', class: 'btn btn-large btn-warning' %>
</div>
<% end %>
goods/_good.html.erb
<%= f.fields_for :goods, #campaign.goods.build, child_index: child_index do |good| %>
<%= good.text_field :name, placeholder: 'Nome' %>
<%= good.text_area :description, placeholder: 'Descrizione' %>
<%= good.text_field :cost, placeholder: 'Costo' %>
<% end %>
campaigns_controller.rb
class CampaignsController < ApplicationController
....
def add_good_row
respond_to do |format|
format.js
end
end
end
add_good_row.js.erb
$('.goods').append("hello");
I think that I understood the problem, it is to pass a f variable, a #campaign variable and a child_index to the partial, but how can I do that via jquery?
Hope I was clear...
Have a look at this gem.
I think it's what you are looking for
https://github.com/nathanvda/cocoon

Error display on ajax form in rails not working

I'm using an inline form for users to submit data to a table (note that I'm using CSS rather than html tables to achieve this). When an error is returned by the verification in the model, I want to highlight the input field using the Bootstrap error class and put the error message below the appropriate form field. I'm using AJAX to submit the form.
I'm having problems, this is what I have so far:
Controller:
def create
#travel = Travel.new(params[:travel])
#travel[:user_id] = current_user.id
convert_date # and return
if #travel.save
flash[:notice] = "Successfully saved trip"
#travels = Travel.where("user_id = ?",current_user)
respond_to { |format| format.js }
end
end
JS view:
<% if #travel.errors.any? %>
<% #travel.errors.full_messages.each { |msg| logger.debug(msg) } %>
<% #travel.errors.messages.each do |k,v| %>
<% logger.debug("#tf_#{k}") %>
$(<%= "#tf_#{k}" %>).insertAdjacentHTML("afterbegin","<span class="control-group error"><span class="controls">");
$(<%= "#tf_#{k}" %>).insertAdjacentHTML("beforeend","</span></span>");
$(<%= "#error_#{k}" %>).val("<%= "#{k} #{v}" %>");
<% end %>
<% else %>
$(":input:not(input[type=submit])").val("");
$("#travels_list").html("<%= escape_javascript( render(:partial => "travels") ) %>");
<% end %>
form partial:
<%= form_for #travel, :remote => true, :html => {:class => "form-inline", :id => "new-travel-form"} do |f| %>
<div class="row-fluid">
<span id="tf_city"><%= f.text_field :city, :placeholder => "London, UK", :class => "span3" %></span>
<span id="tf_arrive_date"><%= f.text_field :arrive_date, :class => "span2" %> </span>
<span id="tf_leave_date"><%= f.text_field :leave_date, :class => "span2" %> </span>
<span id="tf_notes"><%= f.text_field :notes, :placeholder => "e.g. staying at the Hilton", :class => "span3" %></span>
<%= f.submit "save", :class => "btn btn-primary span1" %>
</div>
<% end %>
<div class="row-fluid error" id="error_expl">
<span id="error_city" class="help-inline span3"></span>
<span id="error_arrive_date" class="help-inline span2"></span>
<span id="error_leave_date" class="help-inline span2"></span>
<span id="error_notes" class="help-inline span3">test</span>
</div>
The logger.debug in the JS is firing, so I know that the error is getting passed to the JS, but the insertAdjacentHMTL() doesn't seem to be working.
maybe this is not going to answer your question but i hope it could help to improve your code.
First, according to your code i guess you should have some associations like this in the model User:
has_many :travels
And in your model Travel:
belongs_to :user
So, in order to improve your code you can have this in your controller:
respond_to :js, only: [:create]
def new
#travel = current_user.travels.new
end
def create
#travel = current_user.travels.new(params[:travel])
if #travel.save
flash[:notice] = "Successfully saved trip"
#travels = current_user.travels
else
# I guess you should have some code here in case any validation fail. If you dont
# have validations for the model Travel, you don't need the if statement here.
end
end
About your problem, can you clarify what is "#tf_#{k}"?

Categories

Resources