Rails Photos, Users, Comments - ruby-on-rails

It's driving me crazy. I have 3 models. User, Photo, Comments.
Here is what I want to do.
A user has many photos and comments
A photo belongs to a user and has many comments
And a comment belongs to user and to a photo
So my models have these associations:
User
has_many :photos, :dependent => :destroy
has_many :comments, :dependent => :destroy
Photo
belongs_to :user
has_many :users, :through => :comments
has_many :comments, :dependent => :destroy
Comment
belongs_to :photo, :user
I want now to show a photo and load all the comments of this photo and display each comment with the user info.
So at the photos controller show action I have
#photo = Photo.find(params[:id], :include => :comments, :order => 'comments.created_at DESC')
And in the photo/show view
=render :partial => "/comments/partials/comment", :collection => #photo.comments, :as => :comment
It display the comments eg. the comment text fine but when inside the partial I try to do:
%p=comment.user.fname
%p=comment.body
It throws error "undefined method `fname' for nil:NilClass"
Something strange is that I am user authlogic so you have to be logged in to post a comment. But you can see the comments even if you are not logged in. When I am logged off it works find. When I log in it throws error.
Any help would be much appreciated cause it is driving me nuts.
By the way in my routes I have
map.resources :users, :has_many => [:photos, :comments]
map.resources :photos, :has_many => [:comments, :users]
Thanks

Not sure this will make a difference, but have you tried separating the belongs_to associations?
belongs_to :photo
belongs_to :user

+1 for using haml
i can think of a few reasons why this might happen
firstly, what happens when your remove the following line from your code?
# try removing this
%p=comment.user.fname
Does the error then move on to next variable (i.e. comment.body)
If not, then you have at least narrowed it down to the fname variable. in which case I would wonder if you have perhaps added the fname variable to your model after creating some intitial database entries... this would mean that some of hte entries don't have associated fname variables. in this instance you can fix the issue by scrubbing the database and remigrating from scratch
Also, do you have attr_accessible set for the fname variable in your model? chekc that you have this set for all the variables.
can you look inside your db and make sure that all entries have an fname variable set?
I realise that you want to get this working but if you can't, there's no shame in using the disqus.com plugin - it saves you db space, helps to attract more comments as lots of people already have profiles and gives you some nifty moderator features... on the downside, you lose branding, and you can't use any of your own rjs effects..
good luck

Related

Creating User Profiles

Pretty new to rails, and coding in general. I'm working on my own app right now, in which I'm trying to create user profiles. I know that there have been a few questions about this, but what I'm specifically trying to do is...
Upon authentication (which I've set up using Devise), the user is redirected to his/her profile page where he/she can set up their own profile, with fields similar to what you may find on a social networking website.
I'm running rails 4.1 and ruby 2.1 right now. Does anyone have any suggestions on the best way to go about doing this. As I mentioned I'm fairly new to rails, and have spent the last few days furiously searching for advice on the internet.
Does anyone know of a step by step guide?
I suppose what I need is just guidance on where to start.
Thanks!
You can add other fields like first name, last name, and date of birth to user table itself if you have minimum number of attributes you want to add. You can get all the details from current_user. But if you have many fields that you want to add to user profile then you can create a new model name UserProfile and add other related fields to this model. And add a one-to-one relationship between User and UserProfile table. So in the future if you want to add another relation/attribute with/to user, you can add it with UserProfile. That will reduce making a mess in your database in later stages.
recently i created user profile so that user can add/edit his personal details,see what he has uploaded.what he has liked,posted and edit/delete/update anything that he has created/uploaded.So in user profile all you need is to fetch all details/associated models of that user and show.So as u already have devise..you can get current_user and use user.rb model to understand all associations of user and get the data using associations ans display it on profile page
i have created a profile_controller
so in my nav_bar i have a link_to <% link_to "View Profile",show_profile_path(current_user) %>
where user is directed to profiles controller and i show the details without creating a new model(user has_one :profile)
i have a dedicated page to show profile details + a small page to show any user profile when hovered on users image
take a look here for view side idea... user profile page on bootstrap 3
=======updated part===========
suppose i have a user.rb(using devise)
###different associations of user can be:=
##this user can like/dislike any model having acts_as_votable
acts_as_voter
##user can tags post/audio/videos/images
acts_as_tagger
##my user can create post,pages,upload images/videos/songs/locations etc...
has_many :posts, :class_name => 'Post', :dependent => :destroy
has_many :pages, :class_name => 'Page', :dependent => :destroy
has_many :images, :class_name => 'Image', :dependent => :destroy
has_many :videos, :class_name => 'Video', :dependent => :destroy
has_many :audios, :class_name => 'Audio', :dependent => :destroy
has_many :places, :class_name => 'Place', :dependent => :destroy
has_many :profile_pictures, :class_name => 'ProfilePicture', :dependent => :destroy
#####so..as now i know that **my user can have post/pages/audios/videos** etc...i can also get the details about those associations(assuming you have configured belongs_to in associated models as well + tables with foreign_key as user_id in eash associtated table),such as:-*
##to get all videos that user has uploaded
#user.videos
##same applies for other associated models as well
#user.images..#user.audios...#user.pages.....#user.post....#user.places...#user.profile_pictures...etc
####So now you have all user(current_user data)...
###its time to show data in profiles_controller..
##your show method
## profile#show
def show
#user=User.find current_user.id
#all_user_videos=#user.videos..and so on
##get all user videos/images..etc and show it in your view file
##your view file can be the one that i shared the link or any other way that you want...
###there are lot of ways...google around and then you can get an idea as how to display user_profile page..as now you have the data(*Yipee*)
end##method ends
hope this helps

Rails - combine multiple has_many throughs

I'm just started with Rails, and have a problem I can't solve myself:
User.rb:
has_many :bid_listings, through: :bids, source: :listing, uniq: true
has_many :offer_listings, through: :offers, source: :listing, uniq: true
Both of these return listings, and using methods/scopes from Listing model individually works perfectly. However, when I'm trying to combine these, I'm getting an Array, where i can't apply Listing model's methods and scopes.
I've tried multiple ways, but stuck. Please help.
P.S. User has many bids, User has many offers, bid belongs to listing, offer belongs to listing
You're calling an instance method on an Array object, as opposed to on an ActiveRecord object. Therefore, object of type Array has no idea what the search method is. Try this out:
Edit
user = User.first
listings = Listing.joins(:bids).joins(:offers).where(:bids => {:user_id => user.id}, :offers => {:user_id => user.id})
listings.search('a')
I had a similar problem, and the best solution I came up with was something like:
def buying_listings
Listing.find_by_sql(bid_listings.union(offer_listings).to_sql)
end
This way should still allow you continue scoping, but is less efficient as it will execute an extra query.

Rails active admin for a has_many through association

How can I display the extra attribute of the join model(in a has_many through association), in active_admin forms?
f.input :ad_slots
Will only display the ad_slots model, but I have a join table called stream_slots which has an extra column called duration. I want to be able to choose an ad_slot as well as enter the duration.
These are the models:
#live_stream:
has_many :stream_slots, :dependent => :destroy
has_many :ad_slots, :through => :stream_slots
#ad_slot:
has_many :stream_slots, :dependent => :destroy
has_many :live_streams, :through => :stream_slots
#stream_slot:
belongs_to :ad_slot
belongs_to :live_stream
and stream_slot has the ids of the other two models as well as an extra attribute called duration.
Thank you.
-- Tried something else--
Instead of linking to ad_slots, this is what I did:
f.has_many :stream_slots do |association|
association.inputs do
association.input :ad_slot
association.input :duration
end
end
and in LiveStream class, I added:
accepts_nested_attributes_for :stream_slots
This way the form shows the ad_slots for me to choose from, as well as a text field for the extra attribute, however, It fails when I try to save it. I believe I know what the problem is but I don't know how to solve it. It's because the live_stream_id in the stream_slots table is empty. How do set it to the newly created live_stream? (The one I'm creating now..)
Any help would be appreciated..
I got it working, As mentioned in the question the problem was that when the form was submitted, the live_stream_id was empty.
So I just removed the validation in the stream_slot model which says that the live_stream_id must be present and it worked.
Not sure if that's the best way to do it.. but it's working for now.
If anyone has a better solution, please share.

Trying to get counts through multiple associations

I have created a question an answer app for a client much like StackOverflow. I am not trying to implement some sort of point system (like SO reputation). I am trying to get certain record counts through associations (which I believe are set up correctly). Primarily I am trying to get counts for votes on users answers. Here is an example.
In /views/questions/show page I list all the answers to that question by calling a partial _answer.html.erb. With each answer I pull in the answer.user information (username, email, etc.) by simply doing answer.user.username. I am wanting to display in a badge like format some total point calculations. So if User A answered Question A, next to User A's answer I want to display a total of all User A's answer votes.
I can successfully get a count for a users answers in /views/answers/_answer.html.erb by doing the following:
<%= answer.user.answers.count %>
but when I try to extend that syntax/association to get a count of votes on all User A's answers I get undefined method errors.
<%= answer.user.answers.votes.count %>
Is my set up fundamentally wrong here or am I missing something.
That is a bit confusing so let me know if you need more detail.
UPDATE:
Here are the associations:
Answers
class Answer < ActivRecord::Base
belongs_to :question
belongs_to :user
has_many :votes, :dependent => :destroy
end
Votes
class Vote < ActiveRecord::Base
belongs_to :answer
belongs_to :user
belongs_to :question
end
Users
class User < ActiveRecord::Base
has_many :questions, :dependent => :destroy
has_many :answers, :dependent => :destroy
has_many :votes, :through => :answers , :dependent => :destroy
end
<%= answer.user.answers.votes.count %>
but
answer.user.answers
is an array of answers so I suppose you wanted something like
<%= answer.user.answers[id].votes.count %>
UPDATE
<% answer.user.answers.each do |answer| %>
<%= answer.votes.count%>
<% end% >
UPDATE
<%= (answer.user.answers.map{|x| x.votes.count}).sum%>
I LOVE rails for such things
but when I try to extend that syntax/association to get a count of votes on all User A's answers I get undefined method errors.
You can find complete listing of what you can do with user.answers collection in here (besides standard Array/Enumerable methods). And it's only collection instance, not Answer object, so you can't invoke methods from Answer model on it.
You can try setupping has_many :votes, :through => :answers relationship. (See here for details) Although, I'm not sure if :through would work in such case.
Alternatively, you can create a method in User model to return all Vote objects (simply by iterating through all answers)
But frankly, creating a horde of Vote objects simply to count them sounds like a terrible waste of resources to me.

RESTfully destroy polymorphic association in Rails?

How do I destroy the association itself and leave the objects being associated alone, while keeping this RESTful?
Specifically, I have these models:
class Event < ActiveRecord::Base
has_many :model_surveys, :as => :surveyable, :dependent => :destroy, :include => :survey
has_many :surveys, :through => :model_surveys
end
class ModelSurvey < ActiveRecord::Base
belongs_to :survey
belongs_to :surveyable, :polymorphic => true
end
class Survey < ActiveRecord::Base
has_many :model_surveys
end
That's saying that the Event is :surveyable (ModelSurvey belongs_to Event). My question is, without having to create a ModelSurveysController, how do I destroy the ModelSurvey, while leaving the Event and Survey alone?
Something with map.resources :events, :has_many => :model_surveys? I'm not quite sure what to do in this situation. What needs to happen with the routes, and what needs to happen in the controller? I'm hoping the url could look something like this:
/events/:title/model_surveys/:id
Thanks for your help,
Lance
In Rails 2.3 you have accepts_nested_attributes_for which would let you pass an array of ModelSurveys to the event in question. If you allow destroy through the nested attributes declaration, you'll be able to pass event[model_surveys][1][_destroy]=1 and the association will be removed. Check out the api docs.
Resources domain != model domain
The domain of the controller is not the same as that of the models. It's perfectly fine to update multiple models by changing the state of a resource.
In your case that means doing a PUT or POST to either the Event or the Survey which contains a list of ids for the other. The model for one will update the association.
PUT or POST
Some people (but not Roy Fielding) believe that you should use a PUT to update the resource and provide all of the state again, others feel that a POST with the partial state (ala PATCH) is sufficient.

Resources