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 *
Related
Hello I'm still fairly new to Rails but, currently I have been working on a Rails project for bit now and my last issue with it is when someone clicks on a specific recipe it only shows the very first one a user ever created. I've accessed my database through my console to see if these recipes are saving and they are but when I click on any of the links to a specific recipe it still shows the incorrect one and it won't show the recipe name either.
Here's my recipe controller
class RecipesController < ApplicationController
before_action :require_login
def show
#recipe=Recipe.find_by(params[:name])
binding.pry
end
def index
#recipes =Recipe.all
#binding.pry
end
def new
#recipe = Recipe.new
#recipe.ingredients.build(name: "name")
end
def create
#recipe = Recipe.new(recipe_params)
#recipe.save
#binding.pry
redirect_to recipes_path
end
private
def recipe_params
params.require(:recipe).permit(:id,:name,:content, ingredients_attributes: [
:recipe_id,
:user_id,
:name,
:quantity
]
)
end
end
Index Page
<h1>All Recipes</h1>
<ul>
<% #recipes.each do |recipes| %>
<li><%= link_to recipes.name, recipes %></li>
<% end %>
</ul>
Show Page
<% #recipe.name do |r| %>
<h2> <%= r.name %></h2>
<h2> <%= r.content %></h2>
<%end%>
<h3>Ingredients</h3>
<ul>
<% #recipe.ingredients.each do |ingredient| %>
<li><%= "#{ingredient.name} X #{ingredient.quantity}" %></li>
<% end %>
</ul>
Any help would be appreciated
Thank you!
In your show method it's either one of those
Recipe.find_by(name: params[:name])
# or ...
Recipe.find(params[:id])
...depending on what setup you got going in your routes, the second one is the usual Rails way of doing things.
There are a few issues with your code. In your RecipesController, change the show action code to this:
def show
#recipe = Recipe.find(params[:id])
end
In your index.html.erb view, change the code that iterates through your recipes to this:
<% #recipes.each do |recipe| %>
<li><%= link_to recipes.name, recipe %></li>
<% end %>
And finally, in your show.html.erb view, change the code to this:
<h2><%= #recipe.name %></h2>
<h2><%= #recipe.content %></h>
<h3>Ingredients</h3>
<ul>
<% #recipe.ingredients.each do |ingredient| %>
<li><%= ingredient.name %> X <%= ingredient.quantity %></li>
<% end %>
</ul>
Summary of the changes
In the show action of the RecipesController, you search for the recipe by the id passed in from the view. That id comes from this line:
<%= link_to recipe.name, recipe %>
recipe gets to_param called on it, which returns the id of that particular recipe which you then use in the show action of the RecipesController to find the correct recipe.
In the index.html.erb view, you iterate through all of the recipes, via the #recipes variable, and output each recipe. Since you are outputting each recipe, you normally use recipe instead of recipes as the block variable.
In the show.html.erb view, you don't need to iterate through all recipes because you only have one recipe from the show action of the RecipesController. That recipe is stored in the #recipe variable, so you can use that variable directly in the view.
I'd like to make a list of posts on the app/views/posts/show.html.erb page and sort each by id.
Similar to how all of the posts are listed on my app/views/posts/index.html.erb page using the code block below:
<% #posts.each do |post| %>
<div class="col-md-4">
<%= image_tag post.img %>
<h1><%= post.title %></h1>
<p><%= post.content %></p>
<br>
<%= link_to 'Read More', post_path(post) %>
</div>
<% end %>
When I try to use the same each do method on the show page I get an error. But this is what I currently have (it only displays an img/link to the current post):
<h1>Recent Posts</h1>
<ul>
<li>
<%= image_tag #post.img %>
<h2>
<%= link_to #post.title %>
</h2>
</li>
</ul>
Index is for displaying all the items of x.
def index
#posts = Post.all
end
So what you are doing is taking all your posts, and putting them in an array called #posts. You can iterate or enumerate over those with .each do |x|. That means go through each object in the array and show the post image, title and content.
You didn't display your show, but typically a show looks like:
def show
#post = Post.find(params[:id])
end
So you are finding the post with :id and storing that data in #post. This is only 1 object, it's not an array. That's why your .each do |x| isn't working.
There is nothing stopping you from making
def show
#posts = Post.all
end
But then you can't take advantage of rails shortcuts and are repeating yourself, which isn't good in programming. If you want two very distinct windows that use the same information, it's better to figure that out in html/css with a bit of javascript.
The show action of your PostsController is probably only setting up #post, and not #posts. You can't use .each with #post because it's an instance of Post, and not an array, or something that responds to .each. Look at how #posts is set up in the index action, and copy that to your show action.
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.
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 -%>
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.