Render individual item and collection of items in a view - ruby-on-rails

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)

Related

how am I supposed to use will-paginate with different sized columns?

I want to achieve the following in a rails web app:
In my image, 1 = #article.first, 2 = #article.offset(1).first
So for example:
ArticlesController
def index
#articles = Article.all.paginate(page: params[:page], per_page: 16)
end
Now how am I supposed to achieve this layout in the view?
The use (or not) of will_paginate (or any pagination, for that matter) is irrelevant to how you lay your visual elements out - that's the entire point of the MVC architecture.
The call to paginate makes sure you get one page of 16 results at a time, with the page number controlled by the ?page= parameter in your case.
Elements are often laid out one after the other, which results in a formation using .each:
#articles.each do |article|
render 'articles/article', :article => article
end
In your case, you may need to access the articles in the collection one by one, or even by index. ActiveRecord::Relation collections support array-like access, so to get the first of the sixteen elements you can use articles[0], the second at articles[1], all the way to the sixteenth at articles[15].

Creating Rails todo list app with goals and tasks on one page - missing params

I'm a Rails beginner, and have been reading tutorials and typing out applications for a few months now. I'm really enjoying it after a few years spent in the front end world, and beginning to get up to speed with it all. The time has come though for me to start building my own stuff without any handholding. So far, so good.
I'm creating a basic to-do list app, where goals and tasks are displayed on the same page - goals#index. My issue is that I'm not sure how to get all tasks for a particular goal (that belongs to a user). I understand that I need to pass an ID param to the Goal model in order to find out its tasks, like so:
Goal.find(1).tasks
The above works fine, as I've already set up foreign keys on the tasks table and have a has_many :tasks relationship for the Goal model and a belongs_to relationship for the Task model.
Here's my Goals controller:
def index
#user = current_user
#goals = #user.goals # list all goals for the current user and assign it to the #goals variable.
# Need to find all tasks for each goal ID and assign it to the #tasks variable. Goal ID needs to be supplied here, but it isn't as we're not in show action.
#tasks = Goal.find(1).tasks
As I said, I can find all tasks for a Goal when I manually enter the ID (1 in this example). This works fine in my app, no errors. But obviously I want to supply these IDs dynamically, and I'm just not sure how I get the params in there.
I have tried the below:
#tasks = Goal.find(params[:id]).tasks
and
#tasks = Goal.find(params[:goal_id]).tasks
And I get the "Couldn't find Goal without an ID" error when I try to iterate over #tasks in my view. Which makes sense, as I don't think the goal params are being passed to it as we're not in the Show action.
Surely there must be an easy Rails way?! I'm stumped and don't really know where to look. Thanks for your help and Happy New Year.
You are getting current user's goals, so when you will do this you have one array object. so when you will pass array object to find, it will have multiple IDS. so when need to find All the tasks from all goals you just need to pass Array of IDS instead of single value.
#tasks = Task.where(:goal_id => #goals)
This will run this SQL query.
SELECT "tasks".* FROM "tasks" WHERE "tasks"."goal_id" IN (SELECT
"goals"."id" FROM "goals")
So when you are dealing with array just pass ids. for e.g. [1,2,3]
Once you do #goals = #user.goals (assuming that's working, which it sounds like it is), you have your goals and there is no reason to go back to the DB to "find" them.
To get ALL your tasks from ALL of user's goals, you can do the following:
#tasks = []
#goals.each do |goal|
#tasks << goal.tasks
end
Ah of course, #goals is an array of the user's goals so I can just work with that. So simple when someone just tells you. Thanks for all your help!
Here's my final code that works (I left the controller unchanged). This gets the first goal in the array and then gets the tasks associated with each goal. I have a set number of goals so I can just use goals[0], goals[1] or goals[2] for each goal.
<% #goals[0].tasks.each do |task| %>
<li><div class="task-item"><%= task.task_name %></div></li>
<% end %>

Rails / design array issue

In my 'releases' show view I have the following code:
<% i = #release.id %>
<%= link_to image_tag('next.png'), release_path(i+1), :class => "editRelease" %>
Which takes the user to the next result in the releases table.
I am hoping to only display this 'next' button if an item exists in the array whose id value is one greater than the current release.
Happy to re-write this section of the view / place code in model,controller,helper definition.
Just trying to learn the correct rails way to solve this issue!
Thank you!
Records can be deleted, leaving gaps in your range of ID's, as such using a direct id+1 could point to a null record.
Instead you should define a next method in your model that safely returns the next object. If you don't have any ordering then you can use a query like the one posted in this answer.

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] }

Extra, unwanted field from haml block rails partial

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)

Resources