I have a one-to-many relationship in my rails application:
I have a User class that can have many Devices
I have a Device class that belongs to a User
My Models are designed like this:
class User < ActiveRecord::Base
has_many :devices
end
class Device < ActiveRecord::Base
belongs_to :user
end
Regarding views, when I want to display all Users and list their associated Devices I use this code:
<%= user.devices.each do |device| %>
<%= device.id %>
<% end %>
The output is: (only 1 device right now)
1 #<Device:0x101f45e50>
What I do not understand is why
#<Device:0x101f45e50>
is showing up after the id
replace equal sign
<% user.devices.each do |device| %>
<%= device.id %>
<% end %>
To give a litte more context so you know why this occurred, the = parses the output AND displays the result from the statement in the resulting HTML, where the - parses the line but does NOT display the result — since ruby passes a result at every new statement, you must put your = and - in the right spots.
Documentation is your friend (this is for HAML, but is still a good explanation)
Related
I've been looking for a solution for a few days, in a Rails 4.1 app, so here is my question :
In a Rails app, I have my model User and Adress.
class User < ActiveRecord::Base
has_many :adresses
accepts_nested_attributes_for :adresses
class Adress < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
In my form, I make a form_tag for User, no problem.
But, how I can display to the final user, in a form, 2 adresses fields?
I use <%= f.fields_for :adress %> to display one, it's ok. But if I display two forms (so the user can enter 2 adresses) they have both the same name and the request post only keep one.
I read the doc at http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
but, still, I don't get it.
Is there a proper way to do it?
Thanks
I would suggest you to prepare two addresses in new action, add them to the use and then in the form reneder it with foreach.
I found this kind of solution here : http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Since you have multiple addresses I think foreach is way to go.
So, to help anyone who is noob in Rails and stuck the same way I was :
In your controller :
#user = User.new
#user.adresses = Adress.new, Adress.new
In your view, form :
<%= form_for #user do |f| %>
<%= f.fields_for :adresses do |a| %>
<%= wp.text_field :name %>
<% end %>
<% end %>
will print the name field for adress two times.
(thanks again to #NickCatib)
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 %>
I have two tables: Persons and Statuses and have created two classes Person and Status. I am using following code to show the error message "Only one status is allowed". The code is not working - I think there is some problem in my If statement.
<ul>
<% Person.all.each do |person| %>
<li>
<%= person.name %>
<% if status.size >= 1 %>
<em>Only one status is allowed</em>
<% end %>
</li>
<% end %>
</ul>
Table Persons
U_Id Name Place
1 James Florida
2 Mark California
3 Steve Newyork
Table Statuses
Id Status U_Id
1 Hi 1
2 OMG 2
3 Bye 3
4 Help me 2
Problem: Mark has posted 2 status his U_Id is 2, I want to show him a error message like Only one post is allowed. How this can be done?
Update:
Person class
class Person < ActiveRecord::Base
validates_presence_of :name
end
Your programming logic is incorrect. You are trying to impose a limit on the number of status messages a user can have, but it seems you are enforcing that limit too late, because you are printing an error message when the status is displayed rather than when it is submitted. The people viewing these messages are presumably other users and they hardly care if Mark violates your design constraints.
You have two options.
Limit the number of statuses one a user can have to one.
class User < ActiveRecord::Base
has_one :status
end
This will allow you to do:
steve = User.find(3)
steve.status
=> "Bye"
Only display the last one
Alternatively, you can allow unlimited statuses, but only display the latest one.
class User < ActiveRecord::Base
has_many :statuses
end
mark = User.find(2)
mark.statuses.last
=> "Help me"
On a side note... if users truly only have one status and the former statuses do not matter, then you should consider removing the status model and including the status as a string attribute on the user model. This will, in most cases, improve database performance.
I agree with Stas. status.size will not know what "status" is referring to. It seems like you are trying to refer to the status of each individual person, so you would need something like "person.status.size >= 1".
However, looking at your Person Class, it looks like you might not have the relationship set up yet. You need to include code in your Person class specifying that a Person has_many :statuses. So first do this and make sure that User.first.statuses works, then add the similar code to your views.
in user.rb I admit you have has_many : statuses
and in status.rb, belongs_to :user
<ul>
<% Person.all.each do |person| %>
<li>
<%= person.name %>
<% if person.statuses.size >= 1 %>
<em>Only one status is allowed</em>
<% end %>
</li>
<% end %>
</ul>
but if you want a person to have only one status, why don't you check this when a status is created? or better, when he is trying to access the new action for status check if he has a status and redirect him back with a message saying "You have a status,you can have only one."
After this you can easy use:
user has_one :status
statuses_controller check:
def new
if current_user.status.present?
redirect to :back, error: "Only one status for user"
else
#status = current_user.status.new
end
end
and when doing Person.all.each do |person| you can call directly person.status and it will be first and only one in db without needing to use an if statement. But this depends on how your app should work I guess.
I'm pretty new to rails but started having this issue today which i haven't experienced before. Currently working on an application with a few nested associations. While i can create and add save these nested associations through the parent association i can't seem to call on elements from the associated model very well. I can see the information has been saved but when I call for it i get the name of the model not what is in the name column of the table.
brew.rb
class Brew < ActiveRecord::Base
has_many :fermentables
has_many :extras
has_many :hops
has_many :yeasts
accepts_nested_attributes_for :hops
end
hop.rb
class Hop < ActiveRecord::Base
belongs_to :brew
end
show.html.erb
<%= #brew.name %>
<%= #brew.story %>
<%= #brew.walkthrough %>
<%= #brew.hops.name%>
The show displays mostly everything just fine except when it comes to #brew.hops.name. It only displays Hop.
When I go into rails console I can see that the name had been saved. But only when I do something like.
t = Brew.last
t.hops.name
results only in the word "hops"
but if i just say
t.hops
i get
` SELECT "hops".* FROM "hops" WHERE "hops"."brew_id" = ? [["brew_id", 28]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Hop id: 6, name: "Warrior",
brew_id: 28, created_at: "2013-06-09 22:09:19", updated_at: "2013-06-09 22:09:19">]> `
Brew and hops are in relation one-to-many, so #brew.hops returns set of all hops belonging to #brew. So, if you want to display all associated hops names, you should do something like this:
<% #brew.hops.each do |hop| %>
<%= hop.name %><br />
<% end %>
t.hops returns an object representing the has_many association itself, not an individual Hop record, and calling the name method on that association object gives the name of the class of the associated model (the Hop class).
So I think you are wanting to iterate over the list of associated Hops and print each of their names:
<%- #brew.hops.each do |hop| -%>
Hop: <%= hop.name %>
<%- end -%>
I have a country model and a places model - a country has_many places, and a place belongs_to a country. A place model also has_many posts (which belong_to a place). I would like to aggregate all the posts from places that belong to a certain country into a feed - rather like a friend activity feed on a social networking site. I'm having a bit of trouble figuring out the appropriate search to do, any help would be much appreciated! At the moment I have:
country.rb
has_many :places
has_many :posts, :through => :places
def country_feed
Post.from_places_belonging_to(self)
end
post.rb
belongs_to :place
scope :from_places_belonging_to, lambda { |country| belonging_to(country) }
private
def self.belonging_to(country)
place_ids = %(SELECT place_id FROM places WHERE country_id = :country_id)
where("place_id IN (#{place_ids})", { :country_id => country })
end
end
Then in the country show.html.erb file:
<h3>Posts</h3>
<% #country.country_feed.each do |post| %>
<%= link_to "#{post.user.username}", profile_path(post.user_id) %> posted on <%=link_to "#{post.place.name}", place_path(post.place_id) %> <%= time_ago_in_words post.created_at %> ago:
<%= simple_format post.content %>
<% end %>
This runs without any errors, but gives a feed of all the posts, rather than selecting the posts for that particular country. What's the best way to get this working? I've got a sneaking suspicion that I might be over-complicating matters...thanks in advance!
It looks like there's a syntax error in the subquery. places_id does not exist in the places table, so it really ought to read:
SELECT id FROM places WHERE country_id = :country_id
You'd think the invalid subquery would raise an exception, but it doesn't -- or else it is handled silently. Very odd.
But unless I'm missing something, you could replace all this just by using:
<% #country.posts.each do |post| %>
No?