Object with empty attributes in collection - ruby-on-rails

I have collection of objects fetched from database and when I itterate over it with .each method I get single object with only empty values, like this:
- !ruby/object:List
attributes:
id: 4
title: Test
project_id: 10
created_at: 2013-12-29 20:53:04.087839000 Z
updated_at: 2013-12-29 20:53:04.087839000 Z
- !ruby/object:List
attributes:
id: 5
title: Testng
project_id: 10
created_at: 2013-12-29 20:53:59.087687000 Z
updated_at: 2013-12-29 20:53:59.087687000 Z
- !ruby/object:List
attributes:
id:
title:
project_id: 10
created_at:
updated_at:
What is ok, but... in my SQLite3 database I have only two rows... As doing work around here is not any problem for me I would like to understand why it happens. Could you explain me please?
Here is my controller and partial view in which I am using #current_lists variable
projects_controller.rb
def show
#project = Project.find(params[:id])
#attachment = Attachment.new
#list = #project.lists.new
#current_lists = #project.lists
#current_attachments = #project.attachments
#current_issues = #project.issues.includes(:category)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #project }
end
end
_lists.html.haml
- #current_lists.each do |project|
.col-md-4
.panel.panel-default
.panel-heading
=project.title
.pull-right.text-success
%a.fa.fa-plus.fa-lg
%ul.list-group.task-list
%li.list-group-item.selected
%label.label-checkbox.inline
%input.task-finish{checked: "checked", type: "checkbox"}/
%span.custom-checkbox
SEO Optimisation
%span.pull-right
%a.task-del{href: "#"}
%i.fa.fa-trash-o.fa-lg.text-danger
/ /list-group
EDIT:
That is modal code that I use to render form which uses #list instance variable:
/ /Modal
#newList.modal.fade
.modal-dialog
.modal-content
.modal-header
%button.close{"aria-hidden" => "true", "data-dismiss" => "modal", type: "button"} ×
%h4 Modal with form
.modal-body
=form_for [#project, #list] do |f|
- if #list.errors.any?
#error_explanation
%h2= "#{pluralize(#list.errors.count, "error")} prohibited this list from being saved:"
%ul
- #list.errors.full_messages.each do |msg|
%li= msg
.form-group
= f.label :title
= f.text_field :title, class: 'form-control input-sm'
.form-group
= f.submit 'Save', class: '.btn.btn-success'
/ /.modal-content
/ /.modal-dialog
/ /.modal
Thank you in advance!

You're creating an empty list object in your projects controller with the code:
#list = #project.lists.new
A solution would be to only select saved objects from your #project.lists with:
#current_lists = #project.lists.to_a.select { |list| !list.new_record? }
This will remove unsaved records from your #current_lists array.
Edited to include solution

Related

Rails. SmartListing gem doesn't refresh table after destroying item

I have page with table of categories. I'm using SmartListing GEM for sorting data and also I added some buttons for each item in table, including "delete" button.
Problem: after element in the table was deleted, table blinks but doesn't refresh data, so I need to reload hole page to get updated table. (By the way, element removed from the database without problems)
My files look like the files in developer example.
My files:
index and destroy actions in CategoriesController
def index
#categories = Category.all
smart_listing_create :categories, #categories,
sort_attributes: [
[:created_at, 'categories.created_at'],
[:updated_at, 'categories.updated_at'],
[:name, 'categories.name'],
[:calculate, 'categories.issues_count']
],
default_sort: { name: 'asc' }, partial: 'category'
end
def destroy
#category = Category.find(params[:id])
if #category.issues.empty?
#category.destroy
flash[:success] = 'Deleted'
else
flash[:alert] = 'Category isn\'t empty!'
end
end
index.html.slim
#heading-breadcrumbs
.container
.row
.col-md-7
h1=title 'Categories'
.col-md-5
ul.breadcrumb
li= link_to 'Main', root_path
li Categories
#content
.container
.row
#categories-moderation.col-md-12.col-sm-12.col-xs-12
= link_to 'Create new', new_account_admin_category_path, class: "newcategory btn btn-lg btn-info"
= smart_listing_render(:categories)
_category.html.slim
- unless smart_listing.empty?
.table-responsive
table.table.table-hover.flex-table
thead
tr.centered
th.col-md-2.col-sm-3
= smart_listing.sortable 'Created', :created_at
th.col-md-2.col-sm-3
= smart_listing.sortable 'Updated', :updated_at
th.col-md-4.col-sm-3
= smart_listing.sortable 'Title', :name
th.col-md-2.col-sm-2.hidden-title
= smart_listing.sortable 'Issues', :calculate
th.col-md-2.col-sm-2.hidden-title
| Actions
tbody
- smart_listing.collection.each do |category|
tr.editable[data-id=category.id]
= smart_listing.render object: category, partial: 'category_item', locals: {object: category}
= smart_listing.paginate
- else
p Empty
_category_item.html.slim
tr.centered
td.col-md-2.col-sm-3.col-xs-12.flex-order-0
span.user-label Created:
= object.created_at.strftime("%m.%d.%Y, %T")
td.td.col-md-2.col-sm-3.col-xs-12.flex-order-1
span.user-label Updated:
= object.updated_at.strftime("%m.%d.%Y, %T")
td.lefted.col-md-4.col-sm-2.col-xs-12.flex-order-2
= link_to object.name, object
td.issues_count.col-md-2.col-sm-5.col-xs-12.flex-order-3
span.user-label Issues:
= render partial: 'shared/number_of_issues', locals: { id: object.id }
td.actions.col-md-4.col-sm-5.col-xs-12.flex-order-4
= smart_listing_item_actions [{name: :edit,
url: edit_account_admin_category_path(object),
icon: 'glyphicon glyphicon-pencil',
title: 'Edit'},
{name: :destroy,
url: account_admin_category_path(object),
confirmation: 'Sure?',
icon: 'glyphicon glyphicon-trash',
remote: true, if: object.issue_ids.empty?,
title: 'Delete'}]
index.js.erb
<%= smart_listing_update(:categories) %>
update.js.erb
<%= smart_listing_item :categories, :update, #category, 'category_item' %>
destroy.js.erb
<%= smart_listing_item :categories, :destroy, #category %>
Problem: after element in the table was deleted, table blinks but doesn't refresh data, so I need to reload hole page to get updated table. (By the way, element removed from the database without problems)
I found a solution to the problem. It was resolved simply - just had to add to the destroy action line redirect_to action: 'index', status: 303, so this action should look like this:
def destroy
#category = Category.find(params[:id])
if #category.issues.empty?
#category.destroy
flash[:success] = 'Deleted'
redirect_to action: 'index', status: 303
else
flash[:alert] = 'Category isn\'t empty!'
end
end

Problems with object reflection in nested form with has_many association

I'm trying to implement the has_many pattern shown in "Ruby on Rails Nested Attributes". I'm combining it with some of my own methods and know exactly where it's raising an exception and why. I just don't know how to fix it. I'm using accepts_nested_attributes. I have a class called ProfilePhones.
In profile_email.rb:
def self.attrs
column_names.map(&:to_sym) - [:created_at, :updated_at]
end
The use the above for nested attributes so if the model changes it doesn't break the other controller. In the profiles_controller.rb I have:
def profile_params
params.require(:profile).permit(.... profile_phones_attributes: ProfilePhone.attrs)
In the Profile views folder, I have _profile_email_fields.html.erb with the fields for the ProfilePhone records:
<%= f.text_field :kind, placeholder: "Type" %>
<%= f.text_field :email_address, placeholder: "Email" %>
There's a bit more in this partial, but I'm simplifying it because the partial functions fine. In the main _form partial I have the following:
<%= f.fields_for :profile_emails do |f| %>
<%= render 'profile_email_fields', f: f %>
<%= link_to_add_fields('Add Another Email', f, :profile_emails) %>
<% end %>
In application_helper.rb:
def link_to_add_fields(name = nil, f = nil, association = nil, options = nil, html_options = nil, &block)
f, association, options, html_options = name, f, association, options if block_given?
options = {} if options.nil?
html_options = {} if html_options.nil?
if options.include? :locals
locals = options[:locals]
else
locals = { }
end
if options.include? :partial
partial = options[:partial]
else
partial = association.to_s.singularize + '_fields'
end
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, child_index: 'new_record') do |builder|
render(partial, locals.merge!( f: builder))
end
html_options['data-form-prepend'] = raw CGI::escapeHTML( fields )
html_options['href'] = '#'
content_tag(:a, name, html_options, &block)
end
Finally, in the profiles.coffee:
$('[data-form-prepend]').click (e) ->
obj = $($(this).attr('data-form-prepend'))
obj.find('input, select, textarea').each ->
$(this).attr 'name', ->
$(this).attr('name').replace 'new_record', (new Date).getTime()
return
obj.insertBefore this
false
The problem is in the application_helper method above on the following line:
new_object = f.object.class.reflect_on_association(association).klass.new
f.object.class returns:
ProfileEmail(id: integer, kind: string, email_address: string, profile_id: integer, created_at: datetime, updated_at: datetime)
association is set as :profile_emails. The problem is that this produces Nil. Also, I need to reflect on the model it belongs to Profile. When I switch out with:
Profile.reflect_on_association(association).klass.new
It returns:
-> #<ProfileEmail id: nil, kind: nil, email_address: nil, profile_id: nil, created_at: nil, updated_at: nil>
Which is what I want. However, when I go to the view and click on 'Add another email' link nothing happens. This probably an issue either with my coffeescript or a consequence of calling Profile explicitly. I'm not sure.
My two problems are:
In my reflection method I should be reflecting on Profile and not Profile email, but I'm not sure how to fix it. I can get a string of the profile name, but that doesn't help.
When I explicitly call Profile in the helper method, nothing happens.
one problem seems to be that you have shadowing variable names for the form_builder parameter here:
<%= f.fields_for :profile_emails do |f| %>
<%= render 'profile_email_fields', f: f %>
<%= link_to_add_fields('Add Another Email', f, :profile_emails) %>
<% end %>
try changing to
<%= f.fields_for :profile_emails do |ff| %>
<%= render 'profile_email_fields', f: ff %>
<%= link_to_add_fields('Add Another Email', f, :profile_emails) %>
<% end %>

Values of a book saved from amazon have {:value=>""} around it

I'm making an application where the user can search Amazon (with Vacuum) through my application for books, then be able to record the data of the book to their library.
When you search for a book, it goes through every result and puts each in a thumbnail. In every thumbnail there is a button that opens a modal with a form with hidden tags. When the user clicks the submit button, the book's title is saved into a new book. The only problem is that the title is saved like {:value=>"the title of the book that was saved"}
Here is the part of new.html.erb which has the search box:
<%= form_tag({controller: "books", action: "new"}, method: "get", id: "search-form") do %>
<%= text_field_tag :keywords, params[:keywords], placeholder: "Search for a book", class: "form-control" %>
<% end %>
Here is the part of new.html.erb which has the hidden form:
<% #results.each do |result| %>
…
<%= form_for #book do |f|%>
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
<%= f.submit "Add book", class: "btn btn-default green-hover" %>
<% end %>
…
<% end %>
Here are the new and create actions in my controller:
def new
#book = current_user.books.build if logged_in?
# Search actions
if params[:keywords]
request = Vacuum.new
request.configure(
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
associate_tag: 'my associate tag is here'
)
keywords = params[:keywords]
params = {
'SearchIndex' => 'Books',
'Keywords'=> keywords,
'ResponseGroup' => "ItemAttributes,Images"
}
raw_results = request.item_search(query: params)
hashed_results = raw_results.to_h
#results = []
hashed_results['ItemSearchResponse']['Items']['Item'].each do |item|
result = OpenStruct.new
result.title = item['ItemAttributes']['Title']
result.url = item['DetailPageURL']
result.image_url = item['MediumImage']['URL']
result.author = item['ItemAttributes']['Author']
result.pages = item['ItemAttributes']['NumberOfPages']
#results << result
end
end
end
def create
#book = #list.books.build(book_params)
if #book.save
flash[:success] = #book.title + "was added to your log."
redirect_to list_path(#book.list_id)
else
render 'books/new'
end
end
I tried to use gsub within book.rb to fix it, but that only changed the text within the flash message and it still saved as {:value=>"the title of the book that was saved"}.
after_create :init
private
def init
puts "Init was called!"
self.title.gsub!('{:value=>"', " ")
self.title.gsub!('"}', " ")
end
How can I change it so that it doesn't save the title with the {:value=>} around it?
I don't think the hidden field tag is right.
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
Try
<%= hidden_field_tag :title, result.name %>
Your title is being saved as a hash not a string. Use hash accessing methods:
t = title[:value]
puts t #=> "the tile of the book that was saved"

Locals not set when rendering multiple partials from the same controller

This bug has me perplexed.
I am displaying a Widget with the last 5 data points and a form for a new data_point. When I try to render both the form and the display partial it fails with a routing error. If I comment out either partial it works fine. So with only the form partial it works, or with only the display partial it works fine with the other.
Three relevant models/controllers: Widget, DataSet and DataPoint. DataPoints is STI so I have different partials to display the different types that match the class name.
When both render :partial => ... are uncommented it looks as if the data_point being passed to the second partial is the same as the data_point being passed to the first partial. It is all nil with only a data_set_id. I tried renaming the local from :data_point to :dp in case it was a name collision.
View, both partials and the routing error shown at the bottom.
Is there a limitation on passing :locals to partials when you are trying to render more than one partial in a view?
View: show.html.haml (the show action on the controller is empty)
- title "#{#widget.type.underscore.humanize} for #{#widget.data_set.name.to_s.downcase}"
.row
.span6
= render :partial => 'data_points/form', :locals => { :data_set => #widget.data_set, :data_point => #widget.data_set.data_points.build }
%br
- last_5 = #widget.data_set.data_points.last(5)
- if last_5.count > 0
%h3= "Last #{pluralize( last_5.count, 'Entry' )}"
- last_5.each do |dp|
%pre
= dp.inspect
= render :partial => "data_points/#{#widget.data_set.data_type.underscore}", :locals => { :data_set => #widget.data_set, :data_point => dp }
- else
%h3 No data yet!
= form_tag( push_widget_path #widget, :method => 'POST' ) do
= submit_tag( "Push Data", :class=>"btn btn-primary" )
= link_to "Edit your data", data_set_path( #widget.data_set ), :class=>'btn'
.span6
= image_tag "widgets/#{#widget.type.underscore}.png"
%p
Using the
%b= link_to #widget.data_set.name, #widget.data_set
data set.
= render :partial => "widgets/#{#widget[:type].underscore}", :locals => { :widget => #widget } rescue nil
%p
= link_to 'Edit', edit_widget_path(#widget), :class=>'btn'
Form Partial (data_points/_form.html.haml)
%pre
= data_set.inspect
%pre
= data_point.inspect
= form_for [data_set,data_point], :html=>{:class => 'well form-horizontal'} do |f|
-if data_point.errors.any?
#error_explanation
%h2= "#{pluralize(data_point.errors.count, "error")} prohibited this data_point from being saved:"
%ul
- data_point.errors.full_messages.each do |msg|
%li= msg
= render :partial => "data_points/#{data_set.data_type.underscore}_form", :locals => { :f => f, :data_point => data_point, :data_set => data_set }
= f.text_field :created_at, :type=>'datetime'
.form-actions
= f.submit 'Save'
Display Partial (data_points/_multi_value_data_point.html.haml)
.data-point{ :id=>"data-point-#{data_point.id}"}
%span.value
- data_point.data.map do |k,v|
- label = data_set.properties[:data_series][k][:name]
%span.key= "#{label}: "
= v
.meta
= data_point.created_at
%span.edit
= link_to 'Edit', edit_data_set_data_point_path( data_set, data_point )
%span.delete
= link_to 'Destroy', [data_set, data_point], :method => :delete, :data => {:confirm => 'Are you sure?'}
=# link_to 'Edit', '#', id: "edit-data-point-#{data_point.id}"
:javascript
$("#edit-data-point-#{data_point.id}").click( function(e) {
$("#data-point-#{data_point.id}").html( "#{escape_javascript( render :partial => "data_points/multi_value_data_point_form", :locals => { data_set: data_set, data_point: data_point } )}");
return false;
});
Routing Error
Routing Error
No route matches {:action=>"edit", :controller=>"data_points", :data_set_id=>#<MultiValueDataSet id: 4, ... properties removed ... type: "MultiValueDataSet">, :id=>#<DataPoint id: nil, data: {}, data_set_id: 4, created_at: nil, updated_at: nil>}
Try running rake routes for more information on available routes.
The problem stems from the fact that the form is building a new element that isn't saved, and last is returning that unsaved element.
Simple solution, replace .last(5) with .find( :all, order: 'id desc', limit: 5 )

In my Rails app, JSON formatted results are appearing in a HTML view response

In a Rails 3.1 app, I have a controller returning a set of objects (children) in an index view using this code:
def index
#children = Child.all
#base_class = "children-index"
#title = "Your Children"
respond_to do |format|
format.html # children/index.html.erb
format.json { render :json => #children }
end
end
The index.html.erb view is written like so:
<h1><%= title %></h1>
<ul>
<%= #children.each do |child| %>
<li><%= link_to child.fullname, child_path(child) %></li>
<% end %>
</ul>
For some reason, the JSON response is getting thrown into the HTML response and I cannot determine the reason. None of my other index views are having this issue and their code is very close to the same.
John Jake Smith Jr
Jane Ann Doe
[#<Child id: 1, firstname: "John", middlename: "Jake", lastname: "Smith", suffix: "Jr", gender: "Male", dob_actual: "2011-01-05", dob_expected: "2011-01-01", height: 30, weight: 40, created_at: "2011-10-28 21:32:54", updated_at: "2011-10-28 21:32:54">, #<Child id: 2, firstname: "Jane", middlename: "Ann", lastname: "Doe", suffix: "", gender: "Female", dob_actual: "2011-05-05", dob_expected: "2011-05-01", height: 30, weight: 12, created_at: "2011-11-07 18:08:54", updated_at: "2011-11-07 18:08:54">]
That's not JSON, that's inspect output. You're getting that because each returns #children and you're using <%= here:
<%= #children.each do |child| %>
You want just this:
<% #children.each do |child| %>
Did you forget to do #children.to_json in your controller?

Resources