In my app, I can call a view ('edit.html.erb') using:
<%= link_to( tag.content, [object, tag], method: :patch) %>
What would be the equivalent if I would want to render it within an other view ?
How would I pass it the params?
Edit
In effect I have a view of the parent, in which I want to list the children (editable). These I could edit separately too. Simple solution is that I, create a _partial which I render from the parent's view as well as from edit.html.erb.
I can call this edit.html.erb (or update) using the link:
<%= link_to( tag.content, [object, tag], method: :patch) %>
This works. Now question is how to render that partial (let's call it _update.html.erb) using render? Still need to pass the parent (i.e. object) and child (tag) params. How do I do that using <% render partial "tags/update" PARAMS %>?
Edit for full example
What I am trying to achieve (in short) - allow editing of tags (child) in annotate view (parent).
For an existing record of model/ object "Annotation", I want to add tags for an attached PDF. I do this in a page/view named "Annotate", that I open from the Annotation edit view (using 'link_to'). This "Annotate" page has 2 columns (see screenshot below):
left pane: 2 sections - 1 to quickly add the tag(s) and - 2 to edit existing tags (listed in a table)
right pane: the PDF
Tags and Annotation have polymorphic relationship (set up as per this question)
_form.html.erb for Annotation
<div class="row">
<div class="col-md-6">
<%= simple_form_for #annotation, html: { class: 'form-horizontal', multipart: true },
wrapper: :horizontal_form,
wrapper_mappings: {
check_boxes: :horizontal_radio_and_checkboxes,
radio_buttons: :horizontal_radio_and_checkboxes,
file: :horizontal_file_input,
boolean: :horizontal_boolean
} do |f| %>
<div class="btn-toolbar btn-group", role="toolbar">
<%= f.button :submit, 'Save', :class => "btn btn-xs btn-default" %> <%= link_to 'List' , annotations_path, :class => "btn btn-xs btn-default" %> <% unless #annotation.file.blank? %>
<%= link_to 'Annotate', annotate_path(#annotation), :class => "btn btn-xs btn-default" %>
<% end -%>
</div>
<h4>Annotation</h4>
<%= f.error_notification %>
<% if #annotation.file.blank? %>
<%= f.input :file, as: :file, input_html: { accept: ('application/pdf') } %>
<% else %>
<% end -%>
<%= f.input :name, placeholder: 'Enter name' %>
<%= f.input :description, placeholder: 'Description', :input_html => { :rows => 3 } %>
<%= f.association :documenttype, :collection => Documenttype.active.order(:name), prompt: 'Select document type' %>
<%= f.association :sender, label: 'Submitted by' , prompt: 'Select sender' %>
<%= f.association :receiver, label: 'Specific to', prompt: 'Select recipient' %>
<%= f.input :active, as: :boolean %>
<% end -%>
</div>
<% unless #annotation.file.blank? %>
<div class="col-md-6">
<%= content_tag :iframe, nil, src: pdf_annotation_path(#annotation), width: "100%", height: "770px", frameBorder: "0" %>
</div>
<% end %>
</div>
<% unless #annotation.new_record? %>
<div class="row">
<hr>
<div class="col-md-6">
<%= render #annotation.comments %>
</div>
<div class="col-md-6">
<%= render 'comments/form', :object => #annotation %>
</div>
</div>
<% end -%>
Annotate view annotate.html.erb
<div class="row">
<div class="col-lg-5">
<div class="btn-toolbar btn-group" role="toolbar">
<%= link_to 'Close', annotation_path(#annotation), :class => "btn btn-xs btn-default" %> <%= link_to 'List' , annotations_path, :class => "btn btn-xs btn-default" %>
</div>
<h4>Annotate document</h4>
<div data-spy="affix">
<%= render 'tags/form', :object => #annotation %>
<br>
<div class="panel panel-default" id="annotationResults">
<%= render 'tags/tag_list', :object => #annotation %>
</div>
</div>
</div>
<div class="col-lg-7" id="file">
<%= content_tag :iframe, nil, src: pdf_annotation_path(#annotation), width: "100%", height: "875px", frameBorder: "0" %>
</div>
</div>
tag list _tag_list.html.erb
<table id="tags" class="table table-hover" style="background-color: white; word-wrap: break-word; font-size: 0.9em;" >
<thead>
<tr>
<th>Tagged content</th>
<th>as</th>
<th>in</th>
<th></th>
</tr>
</thead>
<tbody>
<% object.tags.each do |tag| %>
<% unless tag.content.blank? %>
<tr data-tag-id='<%= tag.id %>', class='show-tag'>
<td style="word-wrap: break-word;"><%= link_to( tag.content, [object, tag], method: :patch) %>
<td><%= tag.tagtype.name %></td>
<td><%= tag.tagtype.typeoftag %></td>
<td><%= link_to '', [object, tag], method: :delete, data: { confirm: 'Please confirm!' }, :class => "glyphicon glyphicon-trash" %></td>
</tr>
<tr data-tag-id='<%= tag.id %>', class='edit-tag'>
<td colspan="4"><%= render partial: 'shared/tester' %><%#= render partial: 'tags/update', object: #tag.tagable, tag: #tag %></td>
</tr>
<% end -%>
<% end -%>
</tbody>
</table>
tag update form _update.html.erb
<%= simple_form_for [object, tag], html: { class: 'form-horizontal', multipart: true },
wrapper: :horizontal_form,
wrapper_mappings: {
check_boxes: :horizontal_radio_and_checkboxes,
radio_buttons: :horizontal_radio_and_checkboxes,
boolean: :horizontal_boolean
} do |f| %>
<div class="btn-toolbar btn-group" role="toolbar">
<%= f.button :submit, 'Save', :class => "btn btn-xs btn-default" %>
</div>
<%= f.error_notification %>
tag id = <%= #tag.id %>
<%= f.input :content, placeholder: 'Tagged content'%>
<%= f.association :tagtype, prompt: 'Select tag type', :collection => Tagtype.active.order(:name).where(:documenttype => #tag.tagable.documenttype_id) %>
<%= f.input :location, prompt: 'add as: x1, y1, x2, y2' %>
<% end -%>
Routes
Rails.application.routes.draw do
root 'dashboard#index'
devise_for :users
concern :tagable do
resources :tags, only: [:new, :index, :create, :edit, :update]
end
resources :users, :documenttypes, :tagtypes, :business_partners
resources :tags, only: [:show, :edit, :destroy, :index]
resources :documents do
resources :comments
resources :tags, concerns: :tagable
get "pdf", on: :member
end
resources :annotations do
resources :comments
resources :tags
get "pdf", on: :member
end
get "annotations/:id/annotate" => "annotations#annotate", as: 'annotate'
Tags controller
class TagsController < ApplicationController
def index
#tags = Tag.all.order(:tagable)
end
def show
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
end
def edit
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tag.update(tag_params)
end
def create
tagable = detect_tagable
tagable.tags.create(tag_params)
redirect_to tagable_path(tagable)
end
def update
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
render 'edit'
# #tag.save
#tag.update(tag_params)
end
def destroy
tagable = detect_tagable
#tag = tagable.tags.find(params[:id])
#tag.destroy
redirect_to tagable_path(tagable)
end
private
def tagable_path(tagable)
case tagable
when Document
document_path(tagable)
when Annotation
annotate_path(tagable)
else
fail 'Unknown tagable'
end
end
def detect_tagable
if params[:annotation_id]
Annotation.find(params[:annotation_id])
elsif params[:document_id]
Document.find(params[:document_id])
else
fail 'Tagable not found'
end
end
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id, annotation_attributes: { annotation_ids:[] }, document_attributes: { document_ids:[] })
end
end
This is what I have made - if there is a better way in Rails (which I can image) more then willing to learn.
The approach taken here should be to use nested forms, accepts_nested_attributes_for with allow_destroy: true and reject_if for the validations.
to destroy nested records, use accepts_nested_attributes_for :tags, allow_destroy: true and ensure that (besides :id) also :_destroy
is added to strongparams
to use validations for nested fields, use
accepts_nested_attributes_for :tags, allow_destroy: true,
reject_if: :something_to_check
i'm trying to show all the videos in my app so when i'm adding a new video and want to redirect to movie_path so i did this in my video controller:
def create
#video = Video.new(video_params)
if #video.save
flash[:success] = 'Video added!'
redirect_to movie_path(#movies)
else
render :new
end
end
it gives me an error:
undefined method `any?' for nil:NilClass
this is my show page that want to show the video:
<% if #videos.any? %>
<div class="container">
<div id="player-wrapper"></div>
<% #videos.in_groups_of(3) do |group| %>
<div class="row">
<% group.each do |video| %>
<% if video %>
<div class="col-md-4">
<div class="yt_video thumbnail">
<%= link_to image_tag("https://img.youtube.com/vi/#{video.uid}/mqdefault.jpg", alt: video.title,
class: 'img-rounded'),
"https://www.youtube.com/watch?v=#{video.uid}", target: '_blank' %>
<div class="caption">
<h5><%= video.title %></h5>
<p>Published at <%= video.published_at.strftime('%-d %B %Y %H:%M:%S') %></p>
<p>
<span class="glyphicon glyphicon glyphicon-thumbs-up"></span> <%= video.likes %>
<span class="glyphicon glyphicon glyphicon-thumbs-down"></span> <%= video.dislikes %>
</p>
</div>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
this is movie controller:
def index
#movies = Movie.all.order(:cached_votes_score => :desc)
#movies = #movies.paginate(:page => 1, :per_page => 8)
end
def show
#reviews = Review.where(movie_id: #movie.id).order("created_at DESC")
end
def new
#movie = current_user.movies.build
#movie = Movie.new
#categories = Category.all.map{|c| [ c.name, c.id ] }
end
and this is the routes i have:
nil don't have method any? so you must protect your code against it
instead this line:
<% if #video.any? %>
write this:
<% if #video.try(:any?) %>
I think you have not defined #videos, you have defined #video, so you should try this:
<% if #video.any? %>
#orders should have multiple orders yet when using a respond_to to create an CSV, I only have one order record available in my cvs.erb file. Here's the code.
reports_controller.rb
def orders
params[:q] = {} unless params[:q]
if params[:q][:completed_at_gt].blank?
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
else
params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month
end
if params[:q] && !params[:q][:completed_at_lt].blank?
params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]).end_of_day rescue ""
end
params[:q][:s] ||= "completed_at desc"
#search = Order.complete.ransack(params[:q])
#orders = #search.result
respond_to do |format|
format.html
format.csv do
headers['Content-Disposition'] = "attachment; filename=\"Order-List\"#{Date.today}"
headers['Content-Type'] ||= 'text/csv'
end
end
end
order_items.csv.erb
<%- headers = ['Order Number', 'User', 'Item Total', 'Discount Value', 'Sales Total', 'Promotions'] -%>
<%= CSV.generate_line headers %>
<%- #orders.each do |order| -%>
<%= CSV.generate_line([order.number, order.email, order.item_total, order.promo_total, order.total]) %>
<%- end -%>
order_items.html.erb
<%= search_form_for #search, :url => spree.order_items_admin_reports_path do |s| %>
<div class="form-group date-range-filter">
<%= label_tag nil, Spree.t(:date_range) %>
<div class="date-range-filter row">
<div class="col-md-6">
<%= s.text_field :completed_at_gt, :class => 'datepicker datepicker-from form-control', :value => datepicker_field_value(params[:q][:completed_at_gt]) %>
</div>
<div class="col-md-6">
<%= s.text_field :completed_at_lt, :class => 'datepicker datepicker-to form-control', :value => datepicker_field_value(params[:q][:completed_at_lt]) %>
</div>
</div>
</div>
<div class="form-actions">
<%= button Spree.t(:search), 'search' %>
</div>
<%= link_to "Export CSV", order_items_admin_reports_path(format: 'csv', :params[:q] => params[:q]), {:style => 'margin-top: 50px; margin-bottom: 20px;', :class => "btn btn-primary btn-success"} %>
<% end %>
I have this on my view:
<div class='container'>
<div class='row upper_container'>
<div class='search_container'>
<%= form_tag deals_path, :method => :get, :class => 'navbar-form navbar-left' do %>
<div class='form-group'>
<%= text_field_tag :search, params[:search], class: 'form-control' %>
</div>
<%= submit_tag 'Search', :name => nil %>
<% end %>
</div>
</div>
<% #deals.each_with_index do |d, i| %>
<% if i % 3 == 0 %>
<div class='row middle_container'>
<% end %>
<div class='col-md-4'>
<div class='deal_container'>
<%= d.title %>
<img src='<%= d.photo %>', class='deal_img'>
</div>
</div>
<% if (i % 3 == 2) || (i == (#deals.length - 1)) %>
</div>
<% end %>
<% end %>
</div>
this in my controller:
class DealsController < ApplicationController
def index
# #deals = Deal.paginate(:page => params[:page])
#search = Deal.search do
fulltext params[:search]
end
#deals = #search.result
end
private
def deal_params
params.require(:deal).permit(:title)
end
end
and this in my model:
class Deal < ActiveRecord::Base
searchable do
text :title
end
end
when I want to do a seach by some word, like 'Treatment', the #deals variable, in the controller is null, but the param is being sent: Parameters: {"utf8"=>"✓", "search"=>"Treatment"}
any idea?
Try this:
query = params[:search]
#search = Deal.search do
fulltext query
end
#deals = #search.result
Please check this answer for details.
I'm trying to build a small expense tracking app. Using the nested_form gem to add line items. There is an Expense model which accepts nested attributes. Items belong to expenses and there is a foreign key association. Here's the expense controller:
class ExpensesController < ApplicationController
def new
#expense = Expense.new
#item = #expense.items.build
end
def index
#expenses = Expense.all
##items = Item.where(:expense_id => #expense.id)
end
def show
#expense = Expense.find(params[:id])
#items = Item.where(:expense_id => #expense.id)
end
def create
#expense = Expense.new(expense_params)
respond_to do |format|
if #expense.save
format.html { redirect_to #expense, notice: 'Expense Report Submitted.' }
format.json { render :show, status: :created, location: #expense }
else
format.html { render :new }
format.json { render json: #expense.errors, status: :unprocessable_entity }
end
end
end
def edit
#expense = Expense.find(params[:id])
end
def update
#expense = Expense.find(params[:id])
if #expense.save(expense_params)
flash[:notice] = "Expense Report Updated"
redirect_to #expense
else
render 'edit'
end
end
def destroy
#expense = Expense.find(params[:id])
#expense.destroy
redirect_to 'root'
end
private
def expense_params
params.require(:expense).permit(:department_id, :expense_type_id, :notes, items_attributes: [:id, :description, :amount, :issue_date, :_destroy])
end
end
The form looks like:
<%= nested_form_for (#expense) do |f| %>
<% if #expense.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#expense.errors.count, "error") %> prohibited
this expense from being saved:</h2>
<ul>
<% #expense.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class"row">
<div class="col-md-8">
<div class="form-group">
<%= f.label :department_id %><br>
<%= f.collection_select(:department_id, Department.all, :id, :department_name, prompt: true, class: "dropdown-menu") %>
</div>
<div class="form-group">
<%= f.label :expense_type_id %><br>
<%= f.collection_select(:expense_type_id, ExpenseType.all, :id, :expense_name, prompt: true, class: "form-control") %>
</div>
<%= f.fields_for :items do |i| %>
<div class="form-group">
<%= i.label :description%>
<%= i.text_field :description, class: "form-control" %>
</div>
<div class="form-group">
<%= i.label :amount%>
<%= i.text_field :amount, class: "form-control" %>
</div>
<div class="form-group">
<%= i.label :issue_date%>
<%= i.date_select :issue_date, class: "form-control" %>
</div>
<%= i.link_to_remove "Remove", class: "btn btn-default" %>
<% end %>
<div><p><%= f.link_to_add "Add Expense", :items, class: "btn btn-default" %></p></div>
<div class="form-group">
<%= f.label :notes %>
<%= f.text_area :notes, class: "form-control" %>
</div>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
When I hit submit, the expense and items are saved. I checked with Sqlite browser and the foreign key values are captured for each item.
The index file looks like:
<% #expenses.each do |expense| %>
<tr>
<td><%= expense.item.description %></td>
<td><%= number_to_currency(expense.item.amount) %></td>
<td><%= expense.item.issue_date %></td>
<% end %>
I tried the usual combinations (like expense.item.description) by passing through a block, but they aren't working. I would like to know how to display the expense and the associated items in the show and index pages.
Looking at your new action, in your models you would have
class Expense < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items
end
So when you are doing expense.items in your view it gives you an active record relation(since expense has many items), try this:
<% #expenses.each do |expense| %>
<% expense.items.each do |item| %>
<tr>
<td><%= item.description %></td>
<td><%= number_to_currency(item.amount) %></td>
<td><%= item.issue_date %></td>
</tr>
<% end %>
<% end %>