Hey guys, so I have two models in my project, grinders, and votes.
So each grinder has many votes, and votes belongs to grinder.
The votes table has 3 columns: grinder_id:integer, choice:string, and voter_ip:string
How and WHERE can I make a method for my grinders? I want to be able to do something like
<% #grinders.each do |grinder| %>
<%= grinder.votes_up %>
<% end %>
Where do I define this?
def self.votes_up
grinder.votes.find(:all, :choice => "up").count
end
If that is the right way to do it, correct me if I'm wrong, please.
inside app/models/grinders.rb you should write
class Grinder < ActiveRecord::Base
def votes_up
count "choice = 'up'"
end
end
Related
I'm new to Rails and I'm teaching myself how to use it by working on my own project.
I have a model called Users that has a one-to-many relationship with a model called Pets. The Pets model has a belongs_to relationship to User. I'm trying to build a page where a user can see the list of all Pets. How can I go about doing that?
Thanks.
I agree with Tamer Shlash. It sounds like you'd benefit from practicing a tutorial to get more exposure to model-view-controller (MVC) concepts, and interacting with a database.
Since you want all users to see all pets, Pet.all will return all rows of the pets table.
In a controller action, assign #pets to Pet.all then use that instance variable to loop through the pets and display information about them.
<ul>
<%= #pets.each do |pet| %>
<li><%= pet.name %></li>
<% end %>
</ul>
You'll be best looking at the Rails getting started guide to see how to do this properly. Basically, everything you want to achieve in Rails is done using the MVC programming pattern - each view takes data from the controller, which builds that data from its models
Here is a basic example for you:
Models
#app/models/pet.rb
Class Pet < ActiveRecord::Base
belongs_to :user
end
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :pets
end
--
Routes
#config/routes.rb
resources :pets #-> /pets
--
Controllers
#app/controllers/pets_controller.rb
def index
#pets = Pet.all
end
--
Views
#app/views/pets/index.html.erb
<% #pets.each do |pet| %>
<%= pet.name %>
<% end %>
<% #review.each do |review|%>
<% if review.host_id == #host.id>
<%= #user = User.find(review.user_id) %>
<% end %>
<% end %>
So I'm a bit confused. I have a few things going on here. I'm doing a loop through all reviews of hosts and then checking if the stored host.id value is equal to the active #host object's id that is passed from the controller. Problem is.. Now I need get the user object from the user ID stored in the review but, I'm unsure exactly how to do it. I can't do it from the controller as all this is done in the loop. As you can see I tried to do it with the code above but, I highly doubt I did it right. Please help me out on this. Thanks.
You should pre-load users with loading reviews, in controller. First, you should have belongs_to association, like this:
class Review < ActiveRecord::Base
belongs_to :user
# ...
end
then, in controller, you could use includes, this way:
#reviews = Review.includes(:user)
Now, for every review record in #reviews relation, to get associated user you can call user method, like this:
review.user
What's more, (and that's advantage of using includes) it doesn't fire new SQL query for every single review, so you avoid quite common N + 1 problem.
You can make a relationship in
class Review < ActiveRecord::Base
belongs_to :user
end
and then in view
review.user #gives you user
Put association in Review Model
class Review < ActiveRecord::Base
.
.
.
belongs_to :user
.
.
.
end
After putting association you can directly call association to find user object using Review object.
review.user
But this will raise N+1 query problem, so better user include user while finding review, It will execute only two queries one for finding reviews and another for finding users.
#reviews = Review.includes(:user)
I'm looping through a table to get some values, and then I'm trying to loop another table to get more items:
My Business table looks like this
id name
1 Business 1
2 Business 2
Business Photo table:
id default_pic business_id
1 blahblah.jpg 1
So if I'm trying to loop:
<% #b.each do |b| %>
<%= b.name %>
<%= b.business_photos.default_pic %>
<% end %>
I get undefined method defaul_pic? I believe because there's no more record after the second loop when its getting Business 2. Whats the rails way to check record association so I don't get this error?
This is how my models look:
class Business < ActiveRecord::Base
has_many :business_photos
end
class BusinessPhoto < ActiveRecord::Base
belongs_to :business
end
<%= b.business_photos.default_pic if defined?(b.business_photos.default_pic) %>
This is a conditional if statement we use each time we want to include a variable & are unsure of whether it's set. I've been looking for something which can prevent the error from showing through a .each (would take out so much logic from views), but I am yet to find one
I'm working in Rails and Activerecord and trying to merge some data from related tables together in my view, here are my models:
class Report < ActiveRecord::Base
has_many :votes
end
class Vote < ActiveRecord::Base
belongs_to :reports
end
class User < ActiveRecord::Base
has_many :votes
end
Each vote has a user and a report.
In my view I need the following, hopefully as easily as possible:
a total number of votes for each report from all users
a true/false if the user has voted on the particular report
Right now, my basic understanding of ActiveRecord queries only takes me as far as creating a helper with the report and the current user and than querying for the existence of report
Same goes for counting the total number of votes for all users for a report as follows:
Controller
def index
#this is where I need some help to get the related information into a single
#object
#reports = Report.where('...')
end
View
<% #reports.each do |report| %>
<% if(hasVoted(#current_user.id, report.id)) %>
<!-- display the 'has voted html' -->
<% end %>
<% end %>
Helper
def hasVoted(current_user_id, report_id)
if(Vote.exists?(:user_id => current_user_id, :report_id => report_id))
true
else
false
end
end
Hope that gives you some insight into helping...thanks!
Sure.
Firstly, please consider naming your method has_voted? instead of hasVoted. Secondly, consider moving that method in the user model.
#user.rb
def voted_on?(report_id)
votes.where(:report_id => report_id).exists?
end
Your view will then read
<% if current_user.voted_on?(report) %>
...
<% end %>
The other question you had was to find the number of votes a report has received. This is simple too. You could do this in your view inside the loop where you iterate over #reports
<% vote_count = report.votes.size %>
Please keep in mind that his would result in N queries (where N = number of reports). Since you are new to Rails i'm not going to complicate your Reports query in the controller where you fetch you reports to include the vote count (unless you ask me to). But once you are comfortable with what happening in here, thats where you would optimize.
I have 2 equal-access models: Users and Categories
Each of these should have the standard-actions: index, new, create, edit, update and destroy
But where do I integrate the associations, when I want to create an association between this two models?
Do I have to write 2 times nearly the same code:
class UsersController << ApplicationController
# blabla
def addCategory
User.find(params[:id]).categories << Category.find(params[:user_id])
end
end
class CategoriessController << ApplicationController
# blabla
def addUser
Category.find(params[:id]).users << User.find(params[:user_id])
end
end
Or should I create a new Controller, named UsersCategoriesController?
Whats the best practice here? The above example doens't look very DRY.... And a new controller is a little bit too much, I think?
Thanks!
EDIT:
I need to have both of these associations-adding-functions, because f.e.
#on the
show_category_path(1)
# I want to see all assigned users (with possibility to assign new users)
and
#on the
show_user_path(1)
#I want to see all assigned categories (with possibility to assign new categories)
EDIT:
I'm taking about a HBTM relationship.
If you have a situation where you need to do this with has_and_belongs_to_many, you could take the approach you are currently using, or you could build this into your existing update actions.
When you add a habtm relationship, you will get an additional method on your classes...
class User < ActiveRecord::Base
has_and_belongs_to_many :categories
end
With this, you can do this:
user = User.find(params[:id])
user.category_ids = [1,3,4,7,10]
user.save
The categories with those ids will be set. If you name your form fields appropriately, the update can take care of this for you if you want to use checkboxes or multiselect controls.
If you need to add them one at a time, then the methods you've built in your original post are reasonable enough. If you think the repetition you have is a code smell, you are correct - this is why you should use the approach I outlined in my previous answer - an additional model and an additional controller.
You didn't mention if you are using has_and_belongs_to_many or if you are using has_many :through. I recommend has_many :through, which forces you to use an actual model for the join, something like UserCategory or Categorization something like that. Then you just make a new controller to handle creation of that.
You will want to pass the user and category as parameters to the create action of this controller.
Your form...
<% form_tag categorizations_path(:category_id => #category.id), :method => :post do %>
<%=text_field_tag "user_id" %>
<%=submit_tag "Add user" %>
<% end %>
Your controller...
class CategorizationsController < ApplicationController
def create
if Categorization.add_user_to_category(params[:user_id], params[:category_id])
...
end
end
then your categorization class...
class Categorization
belongs_to :user
belongs_to :category
def self.add_user_to_category(user_id, category_id)
# might want to validate that this user and category exist somehow
Categorization.new(:user_id => user_id, :category_id => category_id)
Categorization.save
end
end
The problem comes in when you want to send the users back, but that's not terribly hard - detect where they came from and send them back there. Or put the return page into a hidden field on your form.
Hope that helps.