Ruby on rails if statement for relationship error - ruby-on-rails

im having an issue displaying the name per category with the following code,
Can anyone advise please?
<% if #products.category.name == "categoryname" %>
<% #products.each do | product | %>
<%= product.name %>
<% end %>
<% end %>
I get the following error:
undefined method `category' for #

It appears you're calling the if statement on the #products.all
#products doesn't have a .category I'd assume judging by your error.
You'll need to change the code to this for it to work...
<% #products.each do | product | %>
<% if #products.category.name == "Name Here" %>
<%= product.name %>
<% end %>
<% end %>

I am assuming that #products is an array or AR::Relationship. You probably want/need to loop through that variable. Looks like you are trying to access a specific instance instead of the whole array.
maybe, #products.first.category.name or something like that

Related

Rails attribute on manual array

In my controller I have:
#payment_types = [['Cash' ,'1'], ['Card', '2']]
What I'm trying to achieve is to show in view Cash and Card while writing on database 1 and 2.
In my view I tried:
<% payment_types.each do |payment_type| %>
<%= payment_type %>
<% end %>
which shows ['Cash' ,'1'] ['Card', '2']]
How can I show instead in my view Cash or Card?
I'm not sure if I understand your question, but if you want to show only 'Cash', and 'Card', you can do it by passing another argument (responsible for hash value, I called it _ because it's a convention for unused arguments) to your block, like this:
<% payment_types.each do |payment_type, _| %>
<%= payment_type %>
<% end %>
You could also do it like this
<% payment_types.each do |payment_type| %>
<%= payment_type.first %>
<% end %>

Rails how to make conditional inside iteration?

i'm trying to use a conditional inside a iteration but did not worked so, here the scenario:
in this case if the if the order or the product is present should just show the order and products with the feedback.
but even if is present show the feedback with odata and pdata.
someone know why?
<% #feedbacks.each do |feedback| %>
<% if order.present? && product.present? %>
<% order = feedback.order %>
<% product = order.product %>
<% else %>
<% odata = feedback.odata %>
<% pdata = odata.pdata %>
<% end %>
I guess this is what you are trying to do,
<% #feedbacks.each do |feedback| %>
<% if (order = feedback.order).present? && (product = feedback.product).present? %>
<%= order.title %>
<%= product.title %>
<% else %>
<%= (odata = feedback.odata).name %>
<%= odata.pdata.name %>
<% end %>
<% end %>
Note: title and name are assumed columns, replace it with your required/respected attribute.
Please go through this to understand the difference between various erb tags.
Comparison:
for the if condition you are trying to call order and product directly, which will throw error as they are related to feedback.
<% %> just executes the ruby code, you wanted to print the data so need to use <%= %>.
no need to save them in variable when you are not going to use it. I have saved them while checking the existence of the object in the condition and could use to display without querying the db.

undefined method `value' for #<CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0>

This is so simple but isnt working. What am I missing?
controlelr
#guide = Guide.friendly.find(params[:guide_id])
#category = #guide.categories.friendly.find params[:id]
#items = #category.category_items
view
<% #items.each do |item| %>
<%= item.category_item_values.value %>
<% end %>
gives the no method error of
undefined method 'value' for #<CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0>
There is a values column in the category_item_values table so I'm not sure what the problem is.
item.category_item_values is the CollectionProxy instance (one might think of it as of an kinda array.)
Each category_item has [likely, you did not provide sufficiently enough info to guess more precisely] many values. If the assumption above is correct, here you go:
<% #items.each do |item| %>
<% item.category_item_values.each do |value| %>
<%= value %> # or maybe (depending on your model) <%= value.value %>
<% end %>
<% end %>
You will have to loop over each of the category_item_values to get the result as this suggests <CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0> that your category_item_value is a association.
So you could do something like
<% item.category_item_values.each do |category_item_value| %>
<%= category_item_value.value %>
<% end %>

Scope of each on rails template

I'm new to rails and I'm trying to build a view that will list the parents and related children
Ex:
Passport has many Visas
I want to list information about the passport and the visas that the passport has.
So I have
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<% end %>
<% end %>
I'm getting the error
undefined method `visa_type' for #Passport:0x000000091b8b28
It looks like rails is trying to find the property visa_type for passport, instead of in visa. How does the scope work within each? Can I force it to access visa_type from visa?
I think you're looking for the fields_for form helper. This will allow you to create fields for the relevant visa attributes. Replace your code sample with the following, and you should be all set.
<% #passport_list.each do |passport| %>
# passportFields
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
You can also iterate over the list as follows:
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
<% end %>
For more information on fields_for, check out the link I added above, and to customize further for your use case, check out the "One-to-many" section.
IMO you should always handle the null case of an object.
Something like this if you use rails (present? is a Rails function)...
<% if #passport_list.present? %>
<% #passport_list.each do |passport| %>
passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<%end%>
<%end%>
<% else %>
<p>Nothing to see here</p>
<% end %>
However if your #passport_list is backed by an ActiveRecord Query, you can handle this in the model/helper/controller by returning the .none query on the model. Note that this differs from an empty array because it is an ActiveRecord Scope, so you can chain AR queries onto it
# scope on AR model
def self.awesomeville
where(country_of_origin: "awesomeville")
end
# method queried in controller
#passport_list = Passport.all
if #passport_list.present?
#passport_list
else
Passport.none
end
# additional filtering in view is now possible without fear of NoMethodError
#passport_list.awesomeville
Whereas a ruby Array would raise an error as it would respond to the Array methods.

Rails .each except if

I have a rails table called Movies. Movies are being collected and saved from an API which means that some movies may have a release_date and some may not.
All Movies are being displayed on the home page and they are sorted by {|t| - t.release_date.strftime("%Y%m%d").to_i}
<% #movies.sort_by{|t| - t.release_date.strftime("%Y%m%d").to_i}.each do |movie| %>
<% movie.title %>
<% movie.release_date.strftime("%Y") %>
<% end %>
So this code works fine but only as long as the returned movies have a release date. If they don't have a release date assigned, it gives me the following error.
ActionView::Template::Error (undefined method `strftime' for nil:NilClass):
But im only getting this error if the movie has no release_date.
So how can i add an exception to only display films WITH a release_date, where using strftime would no longer be a problem.
I've tried
<% unless movie.release_date.blank? %>
<% #movies.sort_by{|t| - t.release_date.strftime("%Y%m%d").to_i}.each do |movie| %>
<% #movie.title %>
<% #movie.release_date.strftime("%Y") %>
<% end %>
<% end %>
But that doesn't work as it gives an undefined method for 'movie'
You should be able to use reject to reject nil release_date like follows:
<% #movies.reject{ |m| m.release_date.nil? } %>
Another problem is you are using the variable movie as instance variable #movie within your each block.
Try:
<% #movies.reject{ |m| m.release_date.nil? }.sort_by{|t| - t.release_date.strftime("%Y%m%d").to_i}.each do |movie| %>
<% movie.title %>
<% movie.release_date.strftime("%Y") %>
<% end %>
Update:
And yes, as pointed by #NicolasGarnil in his answer, it's better to do these in SQL side than in ruby side. Select only the required records and let database do the sorting. So you could update your code to be something like:
In controller:
#movies = Movie.where('release_date is not null').order('release_date desc');
Then in your view:
<% #movies.each do |movie| %>
<% movie.title %>
<% movie.release_date.strftime("%Y") %>
<% end %>
For performance reasons you should not be using ruby to sort your records. This should be done at a database level.
You should first ensure that the release_date values are persisted in an appropriate format and then just use Movie.order("release_date desc"). Records with null values will be placed at the end of the results.

Resources