How to show items which belong to the category - ruby-on-rails

I'd like to answer what I'm doing wrong. So, I'm trying to list all products that belong to the category, on the category's page. Here is the code:
<% #product = Product.all%>
<% #product.where("category_id = ?", params[:#category_id]).each do |product| %>
<%= product.title %>
<%end%>
But there is nothing showing up on my page. So, what's wrong?

There is a whole bunch of problems with your code.
1) Read guides for starters.
2) You have to define an instance variable in controller's action, and then in view just use this variable in your loop. I assume, it is index action you have view for. If so,
def index
# this variable will be used in view
#products = Product.where(category_id: params[:id])
end
and then in view
#products.where(category_id: params[:category_id]).each..
Also, Make sure you have in params what you expect (inspect the params if not sure).
3) You do not execute code, so nothing is being output.
In erb to make things being evaluated you either use - or =. You used none of these. Here is how it should look like:
# notice dash at the beginning of the line
<%- #products.each do |product| %>
<%= product.category_id %>
<% end %>

probably you want read :category_id from params, not :#category_id (so it should be params[:category_id], not params[:#category_id]).

Related

Rails - how to write an index view?

I'm having trouble figuring out how to display an index.
In my organisation requests view folder, I have a file called index.html.erb.
In that file, I'm trying to list each organisation request. I've tried each of the following formulations:
<% OrganisationRequest.each do |OrgReq| %>
<% organisation_request.each do |OrgReq| %>
<% #organisation_request.each do |OrgReq| %>
<% #organisation_requests.each do |OrgReq| %>
In each case, I get an error that says:
formal argument cannot be a constant
I thought a constant meant something beginning with a capital letter. 3 of the above attempts don't begin with a capital letter.
It's also confusing to me since in my user index, I have <% User.each %> and I don't get an error message.
Can anyone see what's gone wrong? How do I ask for a list of objects?
If you have your data and view right, you should be able to fix with:
<% #organisation_requests.each do |org_req| %>
...
<% end %>
If we stick Rails conventions, we'd say that, you have a OrganisationRequests controller, has such content.
class OrganisationRequestsController < ApplicationController
...
def index
#your_local_variable = OrganisationRequest.find(...)
end
...
end
That is to say, you need to use, #your_local_variable inside view file.
<% #your_local_variable.each do |o| %>
....
<% end %>
If the variable inside index action is #organisation_requests, use that.

Rails ERB iterate over array

I'm trying to experiment with blocks and how to iterate over collections in ERB. I have a models in a one-to-many relatinship (Channel and their corresponding types).
controller
class HomePageController < ActionController
def index
#channels = Channel.all
end
end
Then in the view, I iterate over all the attributes belonging to a Channel. When I want to print all types, this code gives me the desired output:
view
<% #channels.each do |channel| %>
<% #types.each do |type| %>
<%= Type.find(type).name %>
<% end %>
<% end %>
At first I tried to achieve this by using the yield keyword in a neat one-liner but I couldn't manage to print anything to the browser, only to the console
<% #types.each {|type| yield Type.find(type).name } %>
Is there an equivalent one-liner?
First of all this method is so inefficient, you are doing n-queries, to find each record of type Type instead convert those into an array of types by using a single query in the controller, assume that that array is in type_ids
# controller
#channels = Channel.includes(:types) # avoiding n+1 queries
# view
<% #channels.each do |channel| %>
# some channel info output
<% channel.types.each do |type| %>
<%= type.name %>
<% end %> # types loop
<% end %> # channel loop
As #Almaron mentioned, you could render a partial for more simplification, if you have a partial called _type.html.erb you can call render directly
# view
<%= render channel.types %>
Rails will do all the iterating and rendering.
First of all, this kind of code does not belong to the view. Don't tackle the database from the view (in your case Type.find()). Move it to the controller where it belongs.
The second thing to note is the difference between <%= and <% tags. The first one outputs the returned result, while the second one doesn't. The problem with .each is that it returns the object it has been used on, so in your case if you just go <%= #types.each {|type| Type.find(type).name } %> you'll get the #types array printed out.
If you want to simplify that code, you can use a helper method for iterating and a partial for rendering each item. That way you get something like this
<% collection_iterate #items, 'item_partial' %>

Variable scope in Rails 4 application

I'm learning rails and I have a test app in which I have listings and locations. There's a many-to-many relationship between them. My index page lists the listings, and provides (in construction) filtering functionality that includes checking locations. This is (partially) done with this, in the index.html.erb file:
<ul class = "list-inline">
<% #locations.each do |location| %>
<li> <label class="checkbox"> <input type="checkbox" value="<%= location.id %>" id="inlineCheckbox1"> <%= location.name %> </label></li>
<% end %>
</ul>
It does the job of displaying all locations with a checkbox to the left of each name.
Now, when adding or editing a listing, I need to let the user select which locations, apply to the listing, so I follow the same idea, and in the _form.html.erb file I have the following code as part of the form:
<select class="multiselect" multiple="multiple">
<% #locations.each do |location| %>
<option value="<%=location.id%>"><%=location.name%></option>
<% end %>
</select>
But this time, I get the following error, whenever going to the new or edit pages:
undefined method 'each' for nil:NilClass
with the
<% #locations.each do |location| %>
line being highlighted.
What am I missing?
(I have omitted code that I thought is irrelevant for the issue in order to now overwhelm you, but I may be wrong).
SOLUTION
Thanks for jumping in with your answers. Sorry I couldn't reply before, as I was at work and without access to my code.
I feel very sheepish... I was missing what is now obvious. The code for my New and Edit actions in the controller needed to have:
#locations = Location.all
Most of you said that in one way or another. I had to choose one answer and I did the one that appeared to me as the most straightforward, being also in comments on the question itself. Thanks!
Please double check your action to make sure you have the # variable in your action. I imagine it should be like this
#listing = Listing.find(params[:id])
#locations = #listing.locations
Your #locations is set in your index action, but it does't live forever. Just long enough for the index page to render. You can either set it again in your edit action, or just change your code to this:
<% Location.all.each do |location| %>
You might not be setting your #locations in your new action.
You can set it like this:
#locations = Location.all
In this case, however, I would like to recommend using a collection_select:
<%= f.collection_select(:location, Location.all, :id, :name, {multiple: true})%>
Local Vars
The problem, without seeing your controller or model, will be with your use of a partial
Rails partials don't use the same #instance variables as their parent views - you have to pass local vars to them (probably because they're designed to be used in many parts of an app; consequently passing local vars keeps them consistent):
#Parent
<%= render partial: "form", locals: { locations = #locations } %>
#_form.html.erb
<% locations.each do |location| %>

Ruby on Rails: Record Creation from view error

I have an isolated issue.
I have a table that populates from several different models, it creates links to follow to each respective view.
The code that I have made for each link should be the same, but for some reason, the link isn't showing up under 'Baseline'. I've checked the :create methods for each model, and they mimic each other, and the code from the view is also just a copy - so I'm at a loss as to where to look next. I'm sure that the problem is that the create method is failing, but I don't know where/how.
Here is the code from my view (I'm also pasting the code from FollowUp3Week, because it works):
<% if Baseline.where(subject_id: sub.subject_id).first != nil %>
<%= link_to "edit", baseline_path([Baseline.where(subject_id: sub.subject_id).first]) %>
<% else %>
<%= Baseline.create(subject_id: sub.subject_id) %> #I left the equal for the screenshot.
<% end %>
</td>
<td>
<% if FollowUp3Week.where(subject_id: sub.subject_id).first != nil %>
<%= link_to "edit", follow_up3_week_path([FollowUp3Week.where(subject_id: sub.subject_id).first]) %>
<% else %>
<% FollowUp3Week.create(subject_id: sub.subject_id) %>
<% end %>
</td>
And here is the create method from baselines_controller.rb
def create
#baseline = Baseline.new(params[:baseline])
if #baseline.save
flash[:success] = "Baseline added from create method"
redirect_to baselines_url
else
render 'new'
end
end
I'm also attaching an image of what it looks like. If I remove the equal sign from <%=, the cell will be blank.
EDIT. I'm in the process of removing all of my database queries from the view. Thank you for your comments.
You should really get that Baseline.where out of your view and into the model. AR scopes from the view is a serious no-no in Rails.
In your baseline mode you could do something like:
def empty_subject(subject_id)
where(subject_id: subject_id).first != nil
end
Also, it looks like you're passing arrays into baseline_path and follow_up3_week_path.
Ditch the square brackets.
on Baseline model, put this
def display_name
"#{name}" #whatever you like to show including link
end

Couldn't find Post without an ID

I am trying to get my posts tagged with a certain tag to render. My code in the view is
Views/posts/sports.html.erb
<% my_posts = post.find_by_tag("sports") %>
<%= my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>
my controller for this looks like
def sports
#posts = Post.paginate(:page => params[:page], :per_page => 10)
#post = Post.find(params[:id])
#title = "Newest"
respond_to do |format|
format.html
format.json { render :json => #users }
end
end
I know I have to define the #post variable but I'm not sure what to define it as.
UPDATE
The problem I'm having is a "Couldn't find Post without an ID" error
Second UPDATE
def find_by_tag name
Tag.find_by_name(name).posts
end
Part of the problem, based on what is shown here, is that you are defining instance variables with Post object(s) in the controller, and then not using them for anything in the view. To retrieve a collection of all the posts tagged "sports," you'd do the following in the controller:
#sports_posts = Post.find_by_tag("sports")
and in the view:
<% #sports_posts.each do |post|
etc...
To add pagination, you can just chain that method to the original:
#sports_posts = Post.find_by_tag("sports").paginate(:page => params[:page],
:per_page => 10)
This is different from your snippet, where you define a #posts variable that returns a collection of 10 Post objects, and #post which simply finds a post object based on the id passed by the submitting form params. My guess is that this controller action is not getting created by a form submission, so no params are passed, and therefore params[:id] is nil, hence the error messages you see. In any event, unless you need either of those items in your view (and there's nothing here to suggest they're being used for anything), there's no reason to create them.
What you do need is a collection of posts tagged "sports", which is what the call above accomplishes. It looks like you are trying to do that with post.find_by_tag("sports") in the view. The problem is that you are calling the find_by_tag method on post, which doesn't exist. Post exists - that's the Post class, and probably what you mean to be calling. Just changing post to Post would probably get you where you want, but content retrieval and presentation are better separated if you create your objects in the controller and then use the view to simply render their attribute data (per the example above).
You don't say what's going wrong, you only say what you're trying to do.
A few things to help debug whatever it is you are seeing:
<%= debug(params) if Rails.env.development? %>
In your main layout, this will dump the params hash and may lend a clue.
Also,
rake routes
Make sure you are looking for the right parameter key(s).
In the snippet you provided, you have an equals in front of the my_posts.each ... line, I am not an ERB expert, but I would think you would not want that, instead this:
<% my_posts = post.find_by_tag("sports") %>
<% my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>

Resources