Extra, unwanted field from haml block rails partial - ruby-on-rails

I'm outputting a collection in haml
#- if #fields.count>0
.sfields
#= render :partial=>"sfields/field", :collection=>#fields, :as=>:field
= render #fields
When there are zero fields, there is always one phantom field rendered. When I add 'if #fields.count>0' then when there is zero there is no output, but as soon as I add one field I get two rendered, the one I added and a phantom field.
This is the first I've run into this and I'm not sure what I did that is outputting a phantom field. I remember seeing something similar, but can't remember where I saw it, and my search turned up nothing relevant atm.
EDIT 1:
Contents of partial
.sfield
= field.name
.fielditems
#- fields.items each do |i|
#= render :partial=>"items/item", :locals=>{:i => i}
= render field.items
So, there is always an extra sfield hanging around.
EDIT 2
Abstractly, I have this:
Show action -> partial for fields -> partial for field items -> partial for field item choices, 4 different places pulled into one page.
So fields is a collection of items and an item is a collection of choices. Even after going through and making the renders more rails default (e.g. render #fields, render field.items, etc.) I still have that phantom field. I don't want to hide it with js or something (ack awful), so I need to figure some solution which entails more trial and error and reading.
It works, but is ugly with the phantom field hanging on.
EDIT 3
I've taken several steps back combined everything into one template, sans partials. Still there. Something basic I'm doing wrong or missing is adding this phantom field, so annoying. It isn't necessarily the partials then.
EDIT 4: SOLVED
refined the #fields select in the controller to select only fields attached to the item I'm showing
e.g.
#fields = #showing.fields
to
#fields = #showing.fields(:showing_id=>#showing.id)
I'd still like to know why it was doing that grr...

Your #fields wouldn't be a list of hashes would it?
NOTE: Due to backwards compatibility concerns, the collection can’t be one of hashes. Normally you’d also just keep domain objects, like Active Records, in there.
-- http://api.rubyonrails.org/classes/ActionView/Partials.html

Note EDIT 4: SOLVED
refined the #fields select in the controller to select only fields attached to the item I'm showing
e.g.
#fields = #showing.fields
to
#fields = #showing.fields(:showing_id=>#showing.id)

Related

Creating Table Filters

I have a simple table with 3 columns like so
table
thead
th Element
th Owner
th Progress
tbody
== render :partial => "element_row" :collection => #elements :as => table_element
Each element is unique, and one owner may have several elements. There are a few different types of "progress" e.g. "started", "not started", and "completed".
I want to create a few links that filter the table. For example, I want to create an started link where when the user clicks on the link, the table is filtered down to only show rows where "started" is displayed. Another example of a filter is by owner.
Does anyone have any suggestions for how to do this?
If you're looking for a gem to help you, Ransack is a great, popular, and active project for searching (and by extension, filtering) ActiveRecord data.
If you check out Ernie's demo site you can see how the search parameters modify the URL through GET queries. You could easily create links like your desired started link to mock these GET form requests.
If you want to do this on the server side, add a filter method to the controller that uses link parameters to filter the #elements.
If you selecting #elements from the database using ActiveRecord, you could do:
#elements = Element.where(progress: params[:progress])
If you just want to filter the #elements in memory, you could do:
#elements = #elements.select{ |element| element.progress == params[:progress] }

Render individual item and collection of items in a view

How can I display the details for a task in the same way (using my _task partial) whether the view is using #project.tasks (ie multiple) or just #task (ie individual task)?
My question is similar to this one : How can you make a ruby function accept either an individual item or collection of items and do the same thing?
I tried checking if #project.tasks.is_a? but it complained wrong number of arguments (0 for 1).
Any ideas?
I'm not sure what you want, but I understood that you want to render partial either collection on individual item. So if I right you should follow these steps and everything will work out of box. Let's say you have model Project and it has_many Tasks, the steps are:
Rename your task partial to tasks/_task.html.erb
Use in view (e.g. projects/show.html.erb) render like this: <%= render #project.tasks %>
You able to use also render like this: <%= render #task %>
Note: solution works for Rails >= 3.
If you want to check if the object is an array or not use if #project.tasks.is_a?(Array)

How to define a Form Override for a Chained Form Field in Active Scaffold

Below example is taken from this documentation page:
https://github.com/activescaffold/active_scaffold/wiki/Chaining-Form-Fields
[Example start]
You can set an array of columns to update multiple columns when a column changes, and chain column updates:
class UsersController < ApplicationController
active_scaffold do |config|
config.columns[:author].form_ui = :select
config.columns[:author].update_columns = [:book, :editorial]
config.columns[:book].form_ui = :select
config.columns[:book].update_columns = :format
end
end
In this example, fields for book, editorial and format are updated when author changes, and when book changes only format is updated. A form override which use the new author or book must be defined for editorial and format columns, in other case those fields won’t change when they will be rendered again.
[Example end]
In the example it states "a form override which use the new author or book must be defined".
Question is how to define those form overrides ??
I have read the documentation on https://github.com/activescaffold/active_scaffold/wiki/Form-Overrides, and tried different form overrides, but with no luck so far, i.e. the columns are not being rendered again.
If you can help me with the code for those form overrides needed in the given example, then I should be able to port that to my code.
Here is the solution to my problem:
I followed the example on "https://github.com/activescaffold/active_scaffold/wiki/Chaining-Form-Fields", but when it did not work for my chained columns (when updating the first column all chained columns updates correctly, but when updating the second column then its chained columns renders to blank lists), then I focused (blindly?) on the details explained just below the example as I thought this was the first step to solve my problem: "A form override which use the new author or book must be defined for editorial and format columns, in other case those fields won’t change when they will be rendered again".
This was however not the case, no form override in the helper was needed to get this to work, in the helper the "options_for_association_conditions" is enough. As the example is for v2.4, maybe the form override is not needed anymore in v3.0+.
The solution is in the next paragraph on the example wiki: "Usually only the value of the changed column is sent, if you need another values to render the updated columns, enable send_form_on_update_column and all the form will be sent". My problem was, that the columns which was chained from the second column needed the value from the first column also, so setting up the second column with "send_form_on_update_column" (i.e. sending the whole form, not just its own value) solved my problem.
In the example this would be:
config.columns[:book].send_form_on_update_column = true

Rails way to offer modified attributes

The case is simple: I have markdown in my database, and want it parsed on output(*).
#post.body is mapped to the posts.body column in the database. Simple, default Activerecord ORM. That column stores the markdown text a user inserts.
Now, I see four ways to offer the markdown rendered version to my views:
First, in app/models/post.rb:
# ...
def body
markdown = RDiscount.new(body)
markdown.to_html
end
Allowing me to simply call #post.body and get an already rendered version. I do see lots of potential problems with that, e.g. on edit the textfield being pre-filled with the rendered HMTL instead of the markdown code.
Second option would be a new attribute in the form of a method
In app/models/post.rb:
# ...
def body_mardownified
markdown = RDiscount.new(body)
markdown.to_html
end
Seems cleanest to me.
Or, third in a helper in app/helpers/application_helper.rb
def markdownify(string)
markdown = RDiscount.new(string)
markdown.to_html
end
Which is used in the view, instead of <%= body %>, <%= mardownify(body) %>.
The fourth way, would be to parse this in the PostsController.
def index
#posts = Post.find(:all)
#posts.each do |p|
p.body = RDiscount.new(string).to_html
#rendered_posts << p
end
end
I am not too familiar with Rails 3 proper method and attribute architecture. How should I go with this? Is there a fifth option? Should I be aware of gotchas, pitfalls or performance issues with one or another of these options?
(*) In future, potentially updated with a database caching layer, or even special columns for rendered versions. But that is beyond the point, merely pointing out, so to avoid discussion on filter-on-output versus filter-on-input :).
The first option you've described won't work as-is. It will cause an infinite loop because when you call RDiscount.new(body) it will use the body method you've just defined to pass into RDiscount (which in turn will call itself again, and again, and so on). If you want to do it this way, you'd need to use RDiscount.new(read_attribute('body')) instead.
Apart from this fact, I think the first option would be confusing for someone new looking at your app as it would not be instantly clear when they see in your view #post.body that this is in fact a modified version of the body.
Personally, I'd go for the second or third options. If you're going to provide it from the model, having a method which describes what it's doing to the body will make it very obvious to anyone else what is going on. If the html version of body will only ever be used in views or mailers (which would be logical), I'd argue that it makes more sense to have the logic in a helper as it seems like the more logical place to have a method that outputs html.
Do not put it in the controller as in your fourth idea, it's really not the right place for it.
Yet another way would be extending the String class with a to_markdown method. This has the benefit of working on any string anywhere in your application
class String
def to_markdown
RDiscount.new(self)
end
end
#post.body.to_markdown
normal bold italic
If you were using HAML, for example in app/views/posts/show.html.haml
:markdown
= #post.body
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#markdown-filter
How about a reader for body that accepts a parse_with parameter?
def body(parse_with=nil)
b = read_attribute('body')
case parse_with
when :markdown then RDiscount.new(b)
when :escape then CGI.escape(b)
else b
end
end
This way, a regular call to body will function as it used to, and you can pass a parameter to specify what to render with:
#post.body
normal **bold** *italic*
#post.body(:markdown)
normal bold italic

break down a complex search query in Rails 3

I have a controller which has a lot of options being sent to it via a form and I'm wondering how best to separate them out as they are not all being used simultaneously. Ie sometimes no, tags, sometimes no price specified. For prices I have a default price set so I can work around with it always being there, but the tags either need to be there, or not. etc.
#locations = Location.find(params[:id])
#location = #locations.places.active.where("cache_price BETWEEN ? AND ?",price_low,price_high).tagged_with([params[:tags]).order(params[:sort]).paginate :page => params[:page]
I haven't seen any good examples of this, but I'm sure it must happen often... any suggestions? Also, even will_paginate which gets tacked on last should be optional as the results either go to a list or to a google map, and the map needs no pagination.
the first thing to do when refactoring a complex search action is to use an anonymous scope.
Ie :
fruits = Fruit.scoped
fruits = fruits.where(:colour => 'red') if options[:red_only]
fruits = fruits.where(:size => 'big') if options[:big_only]
fruits = fruits.limit(10) if options[:only_first]
...
If the action controller still remains too big, you may use a class to handle the search. Moreover, by using a class with Rails 3 and ActiveModel you'll also be able to use validations if you want...
Take a look at one of my plugins : http://github.com/novagile/basic_active_model that allows you to easily create classes that may be used in forms.
Also take a look at http://github.com/novagile/scoped-search another plugin more specialized in creating search objects by using the scopes of a model.

Resources