access attributes using has_many relationship - ruby-on-rails

I have a controller which looks something like this:
class EventController < ApplicationController
def index
...
#events = Event.where(['eventdate < ?', DateTime.now]).order("eventdate")
...
end
end
And my model defines the following relationship:
class Event < ActiveRecord::Base
...
has_many :match_items, dependent: :destroy
...
end
I am now trying to access the event_items linked to the events defined in the the instance variable #event in my view as follows:
<h2>Your Events</h2>
<% #events.each do |event| %>​
</br>​<span>​
<%= event.eventdate.to_formatted_s(:rfc822) %>
<%= event.event_items.event_comment %>
​ </span>
<% end %>
the event.event_items.event_comment line throws an error: undefined method 'event_comment' for []:ActiveRecord::Relation
Why can't I not access event_comment as a method?
If I just use event.event_items the line doesn't display an error and shows the whole event_items array with all it's content displayed in my view.
So i thought maybe I can just access the event_commentas part of the array through using:
<%= event.event_items.event_comment[i] %> #where i is the index of event_comment in the array
But this then doesn't return anything in my display.
Any suggestions on how I can access the attribute event_comment stored in my event_items db table? Any help is very much appreciated!

The reason you are getting that error is because event.event_items returns a ActiveRecord::Relation and not an instance of EventComment. Try using:
event.event_items.first.event_comment

Related

Rails 4 issue in includes and fetch associated items

I have an issue with the includes method in Rails.
I have this user model:
class User < ActiveRecord::Base
has_one :account
end
And this account model:
class Account < ActiveRecord::Base
belongs_to :User
end
Now the user model has :id and :names
and the account model has :user_id and :country
In another controller i want to fetch and display all the user names with their countries.
I am using this query
#users = User.includes(:account).where(some condition)
Please tell me what can I add in the query to fetch all the countries associated with the user names?
Thanks in advance
user should be plural in the controller as you are getting list of records . like this
#users = User.includes(:account)
in view you can do this.
<% #users.each do |user| %>
<%= user.names %>
<%= user.account.country %>
<% end %>
As names is user attribute, you can fetch directly, while country is account's attribute, you can fetch using user.account.country
If it gives you error like
NoMethodError (undefined method `account' for #)
then this means you are converting it into an array in controller itself.
Change your code
eg:
#users = User.includes(:account).where('id < 5')
And in View
<% #users.each do |user| %>
<%= user.name %>
<%= user.account.country %>
<% end %>
Whenever we are using includes it by default does an outer join, so there will may be users who does not have any account and you will get error while trying to access user.account.country as user.account is nil and on the nil object it will try to call country method which does not exist.

Display multiple model results in your views in rails app

I'm adding a new model to my equasion and I'm wondering if there is a way to associate two models into one model then display any/all results within a view. For example, here is what I've currently have;
#tweet_category.order("position").each do |tweet|
<%= tweet.title %>
end
just a short example... now what if I added facebook into this. I was first thinking of creating a model thats named stuff then associate it to tweet_category and facebook_category like so;
class Stuff < ActiveRecord::Base
attr_accessible :title
belongs_to :user
has_many :tweet_category
has_many :facebook_category
end
Now in my controller I'm guessing I would do the following;
class StuffController < ApplicationController
def index
#stuff_list = Stuff.find(:all)
end
end
and in my view I would just simply do the following from above view;
#stuff_list.order("position").each do |stuff|
<%= stuff.title %>
end
am I understanding the logic here??? would that work having two models / two tables db.. etc..
First of all, I don't understand why you would need that "stuff" model. It belongs to users and has_many tweet_category and facebook_category, and just does nothing but offering a "title", when your User model could do the job ( I mean, each user could have many tweets and fb category, instead of having one or several "stuff" which has/have many of them ).
Anyway, if you want to make links between your models and then display everything in a view, first in your User model you just have to do :
class User < ActiveRecord::Base
...
has_many :facebook_categories #( I don't know how rails would pluralize it, btw, I'm just making an assumption )
has_many :tweeter_categories
end
and
class Facebook_category
...
belongs_to :user
end
and do the same fot the tweeter category
Then in your controller :
def show_everything #Here it's a custom action, but you can call it wherever you want
#users = User.all
end
And finally in your view :
<% #users.each do |user| %>
<% user.facebook_categories.all.each do |fb_c| %>
<%= fb_c.title %>
<% end %>
<% user.tweeter_categories.all.each do |t_c| %>
<%= t_c.title %>
<% end %>
<% end %>
Maybe just try to grab a better name for your models, so the pluralization doesn't get messy ( and I saw that the ".all" method is deprecated, so maybe replace it with something
Hope it helps !
Edit :
Basically, when you're doing
#users = User.all
What rails' doing is putting every hash defining every "User" in an array. So, if you want to mix two tables' arrays inside a single array, you can do something like this :
#categories = [] << Facebook_category.all, Tweeter_category.all
You will then have an array ( #category ), filled with 2 arrays ( one ActiveRecord relation for Facebook_category and one for Tweeter_category ). Themselves filled with hashes of their model. So, what you need to do is :
#categories.flatten!
Here's the API for what flatten does ( basically removing all your nested arrays inside your first tarray )
Now, you got a single array of hashes, being the informations from both your model's instances. And, if these informations can be ordered, in your view, you just have to :
<% #categories.order("updated_at").each do |i| %>
<%= i.title %>
<% end %>

Loop error in Rails 3

i want to display all posts in Post table with say id=5 ......
controller
user_controller.rb
class UsersController < ApplicationController
# other methods are also present...
def profile
uid=session[:userid] #session contains userid,it is stored in uid....Eg:5
#post=Post.find_by_userid(uid) #Display all posts with userid=5 in Post table.
end
end
view
profile.html.erb
<h1>In Profile</h1>
<%=session[:test]%>
<% #post.each do |p|%>
<%= p.title%>
<%= p.body%>
<%= p.tag%>
<%end%>
when i execute i get an error like....
Showing /Users/Vineeth/QA4/app/views/users/profile.html.erb where line #3 raised:undefined method `each' for #
Please help me fix the error......thanks.
Post.find_by_userid(uid) is same as Post.where(:userid => uid).first, return only one record.
You should use Post.where(:userid => uid)
You're using Post.find_by_user(uid) which is not something you can iterate over. It only returns a single record.
Use something that returns a collection, like Post.where(:userid => uid)

Edit a serialized hash in a form?

I'm serializing a hash that is stored in a settings field in a table, and would like to be able to edit that hash in a form field.
class Template < ActiveRecord::Base
serialize :settings
end
But I just do <%= f.text_area :settings %> then the text area just shows the serialized data instead of the hash.
How can I get the hash to show in the text area?
Maybe setting up another accessor for your model would work.
class Template < ActiveRecord::Base
serialize :settings
attr_accessor :settings_edit
before_save :handle_settings_edit, :if => lambda {|template| template.settings_edit.present? }
def settings_edit
read_attribute(:settings).inspect # should display your hash like you want
end
protected
def handle_settings_edit
# You may want to perform eval in your validations instead of in a
# before_save callback, so that you can show errors on your form.
begin
self.settings = eval(settings_edit)
rescue SyntaxError => e
self.settings = settings_edit
end
end
end
Then in your form use <%= f.text_area :settings_edit %>.
I have not tested any of this code, but in theory it should work. Good luck!
WARNING: Using eval like this is very dangerous, in this example a user could delete the entire Template table with one line in the edit box Template.destroy_all. Use a different method to convert the string to a hash if user input is involved.
... or you could use something like this (without any logic in model):
<% #template.settings.each do |name, value| %>
<div>
<%= label_tag name %>
<%= text_field_tag "template[settings][#{name}]", value %>
</div>
<% end %>
you should use something like
class Template < ActiveRecord::Base
serialize :settings, Hash
end

How can I list all records which belong to another record at the show page?

I have a table of venues and a table of areas, where a venue belongs to an area and an area has many venues.
How can I show all the venues which belong to an area when I view the areas show page?
I thought this would work:
area show.html.erb:
<%= area.venue.name %>, or
<%= area.venue.name, :collection => #area.venues %>
routes:
resources :areas, :has_many => :venues
but it gives an "undefined local variable or method `area'" error or a syntax error.
I'm super new to any programming and rails what am I doing wrong?
Also, I have a venue partial set up but it's being displayed in another part of my app, I would just like the venue names listed without using partials.
Thanks very much for any help its much appreciated!
First, can you show us your areas_controller.rb file please?
Inside your view you can do this by doing:
<% #area.venues.each do |venue| %>
<%= venue.name %>
# etc.
<% end %>
This implies that inside your areas controller, you have a show action that instantiates the #area instance variable.
Something like:
def show
#area = Area.find(params[:id])
end
And by the way, don't put your model relations inside the routes.rb file! You need to put them inside your models.
Area.rb
class Area < ActiveRecord::Base
has_many :venues
end
Venue.rb
class Venue < ActiveRecord::Base
belongs_to :area
end

Resources