Fetching data from has_one model - ruby-on-rails

I have this models:
class User < ActiveRecord::Base
has_one :page, dependent: :destroy
end
class Page < ActiveRecord::Base
attr_accessible :infos, :title, :user_id
belongs_to :user
end
in the page index view, when I do
<%= page.user.name %>
I can get the value, but in the user page view, when I do
<%= user.page %>
I get the object: #<Page:0x000000045a0470>
and when I do <%= user.page.title %> I get the error: undefined method `title' for nil:NilClass
how can I do to get the values from has_many model in the right way?
thanks!

I figure it out:
Not all users has a page, so I do this:
change
<%= user.page.title %>
to
<%= user.page.try(:title) %>
Then it fix the error. =D

Related

Cannot access attributes from associated model rails

I have three models, ingredient, recipe_ingredient and recipy
class Ingredient < ApplicationRecord
has_many :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipy, :dependent => :destroy
belongs_to :ingredient
end
class Recipy < ApplicationRecord
has_many :recipy_steps
has_many :recipe_ingredients, :dependent => :delete_all
end
I am trying to access the ing_name attribute in the ingredients table from recipies show page.
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %>
<%= ing.ingredient.ing_name %>
</p>
def Show from the recipies controller:
def show
#recipe_ingredients = #recipy.recipe_ingredients
end
But I keep receiving the following error msg:
undefined method `ing_name' for nil:NilClass
My ingredient_params:
def ingredient_params
params.require(:ingredient).permit(:ing_name)
end
It does seem to work like this:
<%= Ingredient.where(id: ing.ingredient_id).pluck(:ing_name) %>
But this does not use the connection between the tables if I understand correctly? Any help? Thanks.
You have ingredient nil thats why you got the error.
Must be your controller has some before_action hook to load recipy
class RecipesController < ApplicationController
before_action :load_recipy, only: :show
def show
#recipe_ingredients = #recipy.recipe_ingredients
end
private
def load_recipy
#recipy = Recipy.find(params[:id])
end
end
You can try this to avoid this nil error(undefined method 'ing_name' for nil:NilClass)
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %>
<%= ing.try(:ingredient).try(:ing_name) %>
</p>
From Rails 5 by default you got one required option to make ingredient always not nullable
like below
belongs_to :ingredient, required: true
It will also prevent this error of
class RecipeIngredient < ApplicationRecord
belongs_to :recipy, :dependent => :destroy
belongs_to :ingredient, required: true
end
the problem is because inside your show method #recipy is nil,
here is usually code for show
controller
def show
#recipy = Recipy.find(params[:id]) # --> you missed this line
#recipe_ingredients = #recipy.recipe_ingredients # #recipy will be null without line above
end
view
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %> <%= ing.ingredient.ing_name %> </p>
<% end %>
I would like also add some suggestion to your model relationship as follow since Ingredient and Recipy shows many to many relationship
class Ingredient < ApplicationRecord
# -> recipe_ingredients -> recipies
has_many :recipe_ingredients, :dependent => :destroy
has_many :recipies, through: :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipy
belongs_to :ingredient
end
class Recipy < ApplicationRecord
has_many :recipy_steps
# -> recipe_ingredients -> ingredients
has_many :recipe_ingredients, :dependent => :destroy
has_many :ingredients, through: :recipe_ingredients
end

Accessing model has_many property

I have the following models:
Post.rb
has_many :likes
belongs_to :user
Like.rb
belongs_to :user
belongs_to :post
User.rb
has_many :posts
has_many :likes
I'm trying to query the user likes in the view like this:
<% #user.likes.each do |i| %>
<%= i.post.title %>
<% end %>
and it returns undefined method 'title' for nil:NilClass
I only can reach the array of posts like this:
<% #user.likes.each do |i| %>
<%= i.post %>
<% end %>
Or like this <%= #user.likes.first.post.title %>
I can't understand why I can't reach the "title" or any other property.
Any help?
It seems at least one of #user.likes doesn't have its associated post. So Like#post returns nil, and on that nil object you try to call title which raises an error. If this situation is not desired, you probably have to validate likes so that every Like has its post:
class Like < ActiveRecord::Base
# ...
validate :post, presence: true
if so, you probably should also make sure associated likes are destroyed when the post is destroyed:
class Post < ActiveRecord::Base
# ...
has_many :likes, dependent: :destroy
You also can fetch likes only with associated post like this:
<% #user.likes.joins(:post).each do |i| %>
or use try in view, so that when like without post is reached, no error is raised:
<%= i.post.try(:title) %>
If your like always belongs to post, it would be better to have user association with likes using "through: :posts" option. That is correct way of association in this scenario.
So your code will be as follows:
Post.rb
has_many :likes
belongs_to :user
Like.rb
belongs_to :post
User.rb
has_many :posts
has_many :likes, through: :posts
and then you can access user's likes as:
<% #user.likes.each do |i| %>
<%= i.post.title %>
<% end %>
Which will always contain post title.

How to display text of category, has-one belongs to associaton

Ok i have two models:
class Treatment < ActiveRecord::Base
attr_accessible :category_id, :content, :date, :patient_id
has_one :category
end
class Category < ActiveRecord::Base
attr_accessible :text
has_many :treatments
end
In my application i tried now to display the text of the category instead of the id for each treatment. Among others i tried this:
<% #treatments.each do |f| %>
<%= f.content %>
<%= f.date %>
<%= f.category.try(:text) %>
<% end %>
But i get the error:
SQLite3::SQLException: no such column: categories.treatment_id
So how can i get the text of the category instead of the id? Thanks
It looks as though you've got an issue with your model relationships. If you're after a standard one-to-many relationship then you need to change
has_one :category
to
belongs_to :category
in your Treatment model.

Correct way to nest form for join model?

I'm trying to nest a form for my Producttracklisting has_many through join model in my product show view. What is the correct way to do this? I'm getting various errors for my various failed attempts.
The models are as follows:
class Product < ActiveRecord::Base
has_many :producttracklistings
has_many :tracks, :through => :producttracklistings
end
class Track < ActiveRecord::Base
has_many :producttracklistings
has_many :products, :through => :producttracklistings
end
class Producttracklisting < ActiveRecord::Base
belongs_to :product
belongs_to :track
end
The form is as follows:
<%= form_for(#producttracklisting) do |f| %>
<%= f.label :track_id %>
<%= f.text_field :track_id %>
<%= f.label :product_id %>
<%= f.text_field :product_id %>
<%= f.submit %>
<% end %>
And i'm trying to bring this into product/show using:
<%= render 'producttracklistings/form' %>
With all of the above I get a "undefined method `model_name' for NilClass:Class"
Thanks in advance.
What you're looking for is accepts_nested_attributes in combination with fields_for.
See this RailsCast Part 1 and part 2 for a detailed tutorial.
PS:
I'd suggest to name your model ProductTrackListing, which results in a table named product_track_listings. This is far more readable and "the rails way"

no method error in one to many relationship

models/user.rb
class User < ActiveRecord::Base
has_many :clubs, :dependent => :destroy
has_many :announcements, :dependent => :destroy
end
models/announcement.rb
class Announcement < ActiveRecord::Base
belongs_to :user
belongs_to :club
end
models/club.rb
class Club < ActiveRecord::Base
belongs_to :user
has_many :announcements, :dependent => :destroy
end
controllers/announcements/announcements_controller.rb
def index
#announcements = Announcement.find(:all, :include => [:user, :club])
end
Problem:
When i type this code,
views/announcements/index.html.erb
<% #announcements.each do |announcement| %>
<%= announcement.user.username %>
<% end %>
I get this error:
NoMethodError in Announcements#index
undefined method `username' for nil:NilClass
when i change code to this, it works.
<% #announcements.each do |announcement| %>
<%= announcement.club.user.username %>
<% end %>
Why is the first code is not working? What is the difference between these codes. Thanks.
It looks like you've got an announcement which has no user set, but does have a club which in turn does have a user. Perhaps consider adding a validation to require that the :user_id column on announcement is present.

Resources