Rails - List a all items method in controller - ruby-on-rails

I need to list all my lawns in one page and then all my bookings in another page. I am writing a method in my controller to list my all items in my database but the problem is either it displays 1 in the view or it produces an inheritance error(in the view) . What I have so far is a lawn that has_many bookings (should actually be has one booking) and a booking which belongs to a lawn and everything is controlled through Activeadmin. The error I get is
undefined method `description' for
Lawn::ActiveRecord_Relation:0x007f4451b00a58> I have modified the error a little bit so it can show over here.
Here is my controller code. A lawn has a title and a description so I am not sure why I get the error. I have put 2 different methods for lawn and booking but they are both not working. Here is my controller.
def display_lawns
#lawn = Lawn.all
end
def display_status
#lawn = Lawn.where("selected = ?", "true")
#bookings = #lawn.booking
end
And here is my view file which does not seem to work with the Lawn.all I also have a similar view file for the bookings with a few changes.
<h2><%= #lawn.description %></h2>
<ul>
<% #lawn.bookings.each do |booking| %>
<li>
<%= booking.description %>
<%= button_to "Select", update_booking_path(booking_id: booking), remote: true %>
</li>
<% end %>
</ul>

A couple of hints.
Instead of
#lawn = Lawn.where("selected = ?", "true")
Is better to add a scope in your model.
#lawn is an array of objects, so use plural.
def display_lawns
#lawns = Lawn.all
end
def display_status
#lawns = Lawn.all.where("selected = ?", "true")
end
#lawns is an array, so you can't use #lawn.description
#lawn.first.description works if you need the first item of the array
<h2><%= #lawns.first.description %></h2>
<ul>
<% #lawns.each do |lawn| %>
<li>
<%= lawn.description %>
<%= button_to "Select", update_booking_path(booking_id: lawn.booking), remote: true %>
</li>
<% end %>
</ul>

Lawn.all and Lawn.where(...) return an ActiveRecord::Relation, consisting of multiple lawns.
In your view, you try to display a lawn's description via #lawn.description, but #lawn is not a single lawn object, but a collection of lawn objects, and the collection does not have a description.
Either only show one lawn object, or loop over all the objects in #lawn (and rename it to #lawns).

Related

Rails - Display all questions by category

I have question and category model. Question model has category_id column.
class Question
belongs_to :category
end
class Category
has_many :questions
end
In my controller I have this:
def index
#categories = Category.all
#questions = Question.all
end
I would like to display all categories and all questions that belongs_to specified category. Also, I would like to display question numbers below each category and made links of them and later it will open new page with clicked question.
This is how I tried to do that:
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% #questions.each do |question| %>
<ul>
<li><%= link_to question.id %></li>
</ul>
<% end %>
<% end %>
It should look like this but I get stuck:
Category1
1 2 3 4
Category2
1 2 3 4
Question: How to achieve that I display questions like is show above?
You can do it this way:
Controller:
def index
#categories = Category.all
end
View:
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% category.questions.each do |question| %>
<ul>
<li><%= link_to question.id, question_path %></li>
</ul>
<% end %>
<% end %>
Since you said you want to display all of the categories, and the questions that belong to each of those categories, I'm assuming that the index action that you pasted in comes from your categories_controller.
One solution I can think of would be to change the instance variables inside your index. I don't really see a purpose for having the instance variable that references all of your Question objects. This is the one I'm talking about:
#questions = Question.all
Yea, get rid of that. You should be fine with just
#categories = Category.all
Since you want to display all of your categories, that instance variable is necessary. And since you mentioned you want to also display all of the questions that belong to each category, that instance variable is sufficient with the right view. You were on the right track, but instead, just use the #categories instance variable; forget about #questions. Here is what your view should probably look like (you were on the right track above):
<% #categories.each do |category| %>
<h1><%= category.name %></h1>
<% category.questions.each do |question| %>
<ul>
<li><%= link_to question.id, question_path %></li>
</ul>
<% end %>
<% end %>
Also note that in that first line of code, when you start a block, you don't need the <%= , You only need the <%. That's because that first line of the block is purely ruby in itself, it isn't actually getting printed to the resulting html.
Hope I helped a little bit!
* Also: I saw another answer on here which is missing something: When you use the <%= link_to %> helper, you need to specify the first argument which is the resulting markup (In this case you wanted the question.id) , AND ALSO A SECOND ARGUMENT, which is the path for the link to follow *

Rails - If / Else in view returning both branches

I've an 'if / else' running in my view, based on the current URL of the page, and currently the view is displaying what is should were the 'if' both true and false. It's a little tricky to explain, and I've no idea why this is happening - any explanations / solutions will be greatly appreciated!
Before the code, here's a little background:
I have recipes, each of which have one or more cuisines (via has-many-through relationships)
if the URL is, for example, /italian, I want it to display all recipes with the cuisine 'Italian'
otherwise, if the URL is invalid or doesn't have any recipes with matching cuisines, I want it to display a message stating this
(So far, so straightforward right?)
However, when the code runs, it's correctly printing the right recipes (i.e. French meals won't come up on the /italian url), BUT also printing the error message. Here's the code:
In the controller:
#url = request.path.split('/')[2] #returning 'italian', 'french', etc.
And the view:
<% Recipe.all.each do |recipe| %>
<% recipe.cuisines.each do |recipe_cuisine| %>
<% if recipe_cuisine.name.downcase == #url %>
<p><strong><%= recipe.name.humanize %></strong></p>
<ul>
<% recipe.ingredients.each do |recipe_ingredient| %>
<li><%= recipe_ingredient.name %></li>
<% end %>
</ul>
<p><%= recipe.method %></p>
<% else %>
<p>You've reached an invalid page, please return to <#%= link_to 'the homepage', root_url %></p>
<% end %>
<% end %>
<% end %>
To clarify, I've tested the 'recipe_cuisine.name.downcase == #url' line of code, and it's returning true when it should be, false when it shouldn't.
Does anyone know how to resolve this?
Thanks in advance, Steve.
Edit
Here are the routes that affect this:
Rails.application.routes.draw do
get 'recipes/:cuisine' => 'recipes#cuisine'
resources :recipes
end
You defined the following route:
get 'recipes/:cuisine' => 'recipes#cuisine'
This means when you hit /recipes, it uses the cuisine action of the recipes controller (thanks to 'recipes#cuisine').
You also defined an extra :cuisine after the recipes/, which means if you hit /recipes/italian, then you will have a GET param (named cuisine) available in your controller/view.
Here is how you can use it:
# recipes_controller.rb
def cuisine
#recipes = Recipe.all # (use `Recipe.scoped` if using Rails' version < 4)
if params[:cuisine].present?
#recipes = #recipes.includes(:cuisines).where(cuisines: { name: params[:cuisine] })
end
# other stuff
end
# cuisine.html.erb (view)
<% #recipes.each do |recipe| %>
<p><strong><%= recipe.name.humanize %></strong></p>
<ul>
<% recipe.ingredients.each do |recipe_ingredient| %>
<li><%= recipe_ingredient.name %></li>
<% end %>
</ul>
<p><%= recipe.method %></p>
<% end %>
But there is a flaw in this logic: What if I hit /recipes/frenchAndMexicanPlease ? The params[:cusine] will be equal to "frenchAndMexicanPlease", and your DB does not have any cuisine type named like this. In this case, it would display no recipe at all, since the query #recipes.includes(:cuisines).where(cuisines: { name: params[:cuisine] }) would not match any existing record.
I can obviously provide more explanations about the code and logic I used. Hope this helps!
How many cuisines are in the collection? If there are two, and one of them has a name that is equal to #url then you would see the first branch, while any that don't equal #url would show the second branch. You're evaluating that if statement for each cuisine.

form_for save input values to session variables

I am trying to create a compare functionality for an index of schools. Currently I am using the following code which takes any checked school and adds it to the school_ids[] in the params.
In my gemfile:
gem 'will_paginate'
In my school's index.html.erb:
<%= form_tag compare_path, :method => 'get' do %>
<%= submit_tag "Compare" %>
<ul>
<% #schools.each do |school| %>
<li>
<%= check_box_tag'school_ids[]', school.id %>
<%= link_to school.name, school %><br>
<%= school.city %>, <%= school.state %>
</li>
<% end %>
</ul>
<% end %>
In my school controller I have:
def compare
#schools = School.find(params[:school_ids])
end
This works great as long as all of the check schools are on the same page. But since I'm using will_paginate to paginate the list of schools, if I change pages, the check boxes do not persist. I'm assuming I need to save to sessions somehow.
Do you mean you want to be able to add a check mark to a school A on page 1 of the index, go to page 2 of the index and add another check mark for school B, then submit the compare form and see schools A and B? If that's the case, then you're correct, you need to get the check boxes into the session. Attach a js click event, like
$('.checkbox_class').click(function(){
$.post('update_session_method', { school_id: $(this).val(), checked: $(this).is(:checked)]);
});
then add a controller method
def update_session_method
session[:school_ids] ||= []
if params[:checked]
session[:school_ids] << params[:school_id]
else
session[:school_ids].delete(params[:school_id])
end
end
then your compare method
def compare
#schools = School.find(params[:school_ids].merge(session[:school_ids] || []))
end

rails where condition works in console, but not in web server

I am new in RoR.
The problem is, I created fully functional product categorization with Ancesrty. But now I want to be able to retrieve products that is under these subcategories.
This is my categories show controller
#category = Category.find(params[:id])
Here is categories#show view.
<b>Name of the category:</b>
<%= #category.name %>
<div class="product"
</div>
</p>
<% unless #category.children.empty? %>
<ul id="sub-menu">
<% #category.children.each do |sub1| %>
<%= link_to (sub1.name), sub1 %>
<%end%>
<%end%>
It all works fine. but now I want to add in view categories/show function that shows all products that is under that category.
I added such code.
In category/show controller
#cat_id = #category.id
#product = Product.where("category_id = ?",#cat_id)
In the categories show view I added
<td><%= #product.name %></td>
Then clicking on some subcategory where should appear few products, there just shows up Product
To check if the code is right I put in the console. There it works fine and retrieve products related to this category.
I dont understand why then code not working in webserver when I launch application ?
Could it be because of some erorr in Associations ?
Thanks !
in your controller, a more readable way is to use the plural form to indicate that you are expecting more than 1 object
#products = Product.where("category_id = ?", #cat_id)
Then in the view, just loop through these products
<% #products.each do |product| %>
<%= product.name %>
<% end %>
#product = Product.where("category_id = ?",#cat_id)
will return an array if there are any products. So you will need to loop through the array.
<% #product.each do |product| %>
<%= product.name %>
<% end %>
I accept both of the answers, But I want to suggest to use Active Record Association for this type of problems. This makes your solution easier.
If you want to fetch only one product, you can use the find_by_ helper method of the model:
#product = Product.find_by_category_id(#cat_id)
With this it will fetch the first matching product which has category_id equal to #cat_id.
If you want to fetch all the products which belong to a category, you need to fetch all the products as others suggested:
#products = Product.where(:category_id => #cat_id)
And then in the view:
<% #products.each do |product| %>
<%= product.name %>
<% end -%>

Multiple views in Rails

I have the following problem:
In Rails I have two Objects: Categories and Items
One category has many items and one item belongs to one category.
Okay. There are no problems.
But now, I want to display all existing categories in a sidebar on every page in my project.
I tried to do display them like:
<div class="sidebar">
<% #categories.each do |category| %>
<p><%= link_to category.title, category %></p>
<% end %>
</div>
My root controller is categories. On my starting page the code above will work without any problems.
But when I click on a category I get the following exception:
*You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each*
Extracted source (around line #2):
2: <% #categories.each do |category| %>
How can I fix this problem?
Sorry for my bad English!
You forget to set the #categories variable in the controller.
You can either load the #categories in every action you need to display the sidebar or delegate the request to the view without setting an instance variable.
# in the controller
def action
#categories = ...
end
# or in the view
<div class="sidebar">
<% Category.all.each do |category| %>
<p><%= link_to category.title, category %></p>
<% end %>
</div>
If the code spans over multiple views/controllers, I would suggest you to extract the statement in a before_filter and/or a partial.

Resources