I have an activity feed that currently show all activity including current user. My goal is to only update the feed with friends' activity and not the current user's activity. I believe it has something to do with the map(&:id) method, but I'm not positive. Any guidance would be super awesome!
activity.rb:
class Activity < ActiveRecord::Base
belongs_to :user
belongs_to :targetable, polymorphic: true
self.per_page = 10
def self.for_user(user, options={})
options[:page] ||= 1
# return WillPaginate::Collection.new(1, per_page, 1) unless user
friend_ids = user.friends.map(&:id).push(user.id)
collection = where("user_id in (?)", friend_ids).order("created_at desc")
if options[:since] && !options[:since].blank?
since = DateTime.strptime( options[:since], '%s' )
collection = collection.where("created_at > ?", since) if since
end
collection.page(options[:page])
end
def user_name
user.name
end
def username
user.username
end
def as_json(options={})
super(
only: [:action, :id, :targetable_id, :targetable_type, :created_at, :id],
include: :targetable,
methods: [:user_name, :username]
).merge(options)
end
end
The .push(user.id) is adding the user's own ID onto this list of friend IDs so if you just remove that you'll get the activities for just the friends.
friends.map(&:id) takes the list of the user's friends and maps this to a list of the IDs for those friends ready for use in the where condition on the next line i.e. it calls id on each friend and returns an array of the results of that.
Related
For a quiz application, I am trying to display ACTIVE questions, in which the current user has not answered. The answer table has a user_id and question_id that I'm trying to use. I thought I was close with the following query (in the static_pages_controller.rb:
#questions = Question.active_question.where.not(id: #user.answers)
It seems to not work in all situations when I am testing it though. I feel like I'm close, but not sure where to go from here. Pretty new to Rails so greatly appreciate any assistance!
question.rb
has_many :answers
scope :active_questions, -> { where("? BETWEEN start AND end", Time.now.to_date)}
scope :activeAtDate, lambda{ |date = Date.today| where("? BETWEEN start AND end", date) }
answer.rb
belongs_to :question
belongs_to :user
scope :user_answered, lambda {|q| where("question_id == (?)", q) }
validates_uniqueness_of :question_id, scope: :user_id
user.rb
has_many :answers
static_pages_controller.rb
def index
#user = current_user
if user_signed_in?
if #user.manager_id != nil
#manager = #user.manager_id
end
#my_team = User.where("manager_id = ? AND id != ?", #manager, #user.id)
#questions = Question.active_question.where.not(id: #user.answers)
end
#new_answer = Answer.new
end
Pretty new to Rails
Welcome - you've done very well so far.
I originally thought you should be calling the questions from your #user.answers association - then I realized you wanted questions to which the user had not answered.
...so I'd do the following:
#app/models/user.rb
class User < ActiveRecord::Base
def non_participating_questions
answered_questions = self.answers.pluck(:question_id)
Question.active_questions.where.not(id: answered_questions)
end
end
This will allow you to call:
#user = User.find params[:id]
#questions = #user.non_participating_questions
The benefits of attaching this to the User model is that you can use the instance_method (so you don't have to pass #user each time). It also means you're able to deal with all the associative data a user has as well (answers etc).
I am new to rails developement and to the MVC architecture. I have a little application where I can add Videos' URLs from Dailymotion or Youtube and get the tweets related to that URL using the twitter gem in Ruby on Rails.
Now i'm able to store the tweets like this : (This is the video controller)
def show
#video = Video.find(params[:id])
# Creating a URL variable
url = #video.url
# Search tweets for the given video/url
#search = get_client.search("#{#video.url} -rt")
# Save tweets in database
#search.collect do |t|
tweet = Tweet.create do |u|
u.from_user = t.user.screen_name.to_s
u.from_user_id_str = t.id.to_s
u.profile_image_url = t.user.profile_image_url.to_s
u.text = t.text.to_s
u.twitter_created_at = t.created_at.to_s
end
end
I'm not sure if this is the right way to do it (doing it in the controller ?), and what I want to do now is to specify that those tweets that have just been stored belong to the current video. Also I would like to have some sort of validation that makes the controller look in the database before doing this to only save the new tweets. Can someone help me with that ?
My models :
class Video < ActiveRecord::Base
attr_accessible :url
has_many :tweets
end
class Tweet < ActiveRecord::Base
belongs_to :video
end
My routes.rb
resources :videos do
resources :tweets
end
This is an example of a "fat controller", an antipattern in any MVC architecture (here's a good read on the topic).
Have you considered introducing a few new objects to encapsulate this behavior? For example, I might do something like this:
# app/models/twitter_search.rb
class TwitterSearch
def initialize(url)
#url = url
end
def results
get_client.search("#{#url} -rt")
end
end
# app/models/twitter_persistence.rb
class TwitterPersistence
def self.persist(results)
results.map do |result|
self.new(result).persist
end
end
def initialize(result)
#result = result
end
def persist
Tweet.find_or_create_by(remote_id: id) do |tweet|
tweet.from_user = screen_name
tweet.from_user_id_str = from_user_id
tweet.profile_image_url = profile_image_url
tweet.text = text
tweet.twitter_created_at = created_at
end
end
private
attr_reader :result
delegate :screen_name, :profile_image_url, to: :user
delegate :id, :user, :from_user_id, :text, :created_at, to: :result
end
Notice the use of find_or_create_by ... Twitter results should have a unique identifier that you can use to guarantee that you don't create duplicates. This means you'll need a remote_id or something on your tweets table, and of course I just guessed at the attribute name (id) that the service you're using will return.
Then, in your controller:
# app/controllers/videos_controller.rb
class VideosController < ApplicationController
def show
#tweets = TwitterPersistence.persist(search.results)
end
private
def search
#search ||= TwitterSearch.new(video.url)
end
def video
#video ||= Video.find(params[:id])
end
end
Also note that I've removed calls to to_s ... ActiveRecord should automatically convert attributes to the correct types before saving them to the database.
Hope this helps!
I am attempting to locate a parent object in a nested controller, so that I can associate the descendant resource with the parent like so:
# teams_controller.rb <snippet only>
def index
#university = Univeresity.find(params[:university_id])
#teams = #university.teams
end
When I call find(params[:university_id]) per the snippet above & in line 6 of teams_controller.rb, I receive ActiveRecord::RecordNotFound - Couldn't find University without an ID.
I'm not only interested in fixing this issue, but would also enjoy a better understanding of finding objects without having to enter a University.find(1) value, since I grant Admin the privilege of adding universities.
The Rails Guides say the following about the two kinds of parameters in a website:
3 Parameters
You will probably want to access data sent in by the user or other
parameters in your controller actions. There are two kinds of
parameters possible in a web application. The first are parameters
that are sent as part of the URL, called query string parameters. The
query string is everything after “?” in the URL. The second type of
parameter is usually referred to as POST data. This information
usually comes from an HTML form which has been filled in by the user.
It’s called POST data because it can only be sent as part of an HTTP
POST request. Rails does not make any distinction between query string
parameters and POST parameters, and both are available in the params
hash in your controller:
It continues a little further down, explaining that the params hash is an instance of HashWithIndifferentAccess, which allows usage of both symbols and strings interchangeably for the keys.
From what I read above, my understanding is that Rails recognizes both parameters (URL & POST) and stores them in the same hash (params).
Can I pass the params hash into a find method in any controller action, or just the create/update actions? I'd also be interested in finding a readable/viewable resource to understand the update_attributes method thats called in a controller's 'update' action.
Please overlook the commented out code, as I am actively searching for answers as well.
Thanks in advance.
Here are the associated files and server log.
Webrick
teams_controller.rb
class TeamsController < ApplicationController
# before_filter :get_university
# before_filter :get_team
def index
#university = University.find(params[:univeristy_id])
#teams = #university.teams
end
def new
#university = University.find(params[:university_id])
#team = #university.teams.build
end
def create
#university = University.find(params[:university_id])
#team = #university.teams.build(params[:team])
if #team.save
redirect_to [#university, #team], success: 'Team created!'
else
render :new, error: 'There was an error processing your team'
end
end
def show
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def edit
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def update
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
if #team.update_attributes(params[:team])
redirect_to([#university, #team], success: 'Team successfully updated')
else
render(:edit, error: 'There was an error updating your team')
end
end
def destroy
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
#team.destroy
redirect_to university_teams_path(#university)
end
private
def get_university
#university = University.find(params[:university_id]) # can't find object without id
end
def get_team
#team = #university.teams.find(params[:id])
end
end
team.rb
class Team < ActiveRecord::Base
attr_accessible :name, :sport_type, :university_id
has_many :home_events, foreign_key: :home_team_id, class_name: 'Event'
has_many :away_events, foreign_key: :away_team_id, class_name: 'Event'
has_many :medias, as: :mediable
belongs_to :university
validates_presence_of :name, :sport_type
# scope :by_university, ->(university_id) { where(team_id: team_id).order(name: name) }
# scope :find_team, -> { Team.find_by id: id }
# scope :by_sport_type, ->(sport_type) { Team.where(sport_type: sport_type) }
# scope :with_university, joins: :teams
# def self.by_university(university_id)
# University.where(id: 1)
# University.joins(:teams).where(teams: { name: name })
# end
def self.by_university
University.where(university_id: university_id).first
end
def self.university_join
University.joins(:teams)
end
def self.by_sport_type(sport_type)
where(sport_type: sport_type)
end
def self.baseball
by_sport_type('Baseball/Softball')
end
end
university.rb
class University < ActiveRecord::Base
attr_accessible :address, :city, :name, :state, :url, :zip
has_many :teams, dependent: :destroy
validates :zip, presence: true, format: { with: /\A\d{5}(-\d+)?\z/ },
length: { minimum: 5 }
validates_presence_of :name, :address, :city, :state, :url
scope :universities, -> { University.order(name: 'ASC') }
# scope :by_teams, ->(university_id) { Team.find_by_university_id(university_id) }
# scope :team_by_university, ->(team_id) { where(team_id: team_id).order(name: name)}
def sport_type
team.sport_type
end
end
views/teams/index.html.erb
Placed in gists for formatting reasons
rake routes output: (in a public gist)
enter link description here
rails console
You're not going to want to have both:
resources :universities #lose this one
resources :universities do
resources :teams
end
As for params... you have to give a param. So, when you go to http://localhost:3000/teams there are no params, by default. If you go to http://localhost:3000/teams/3 then params[:id] = 3 and this will pull up your third team.
Keep in mind the nomenclature of an index. The index action of Teams, is going to list all of the teams. All of them. There is no one University there, so what are you actually trying to find? If anything, you'd have, for your University controller:
def show
#university = University.find(params[:id])
#teams = #university.teams
end
so, the address bar will be showing http://localhost:3000/universities/23, right? params[:id] = 23, then you can find the teams associated with that university.
I'm adding a small way of controlling a non-subscribed user and a subscribed user. Basically my idea is that all users that sign up with the use of Devise, get an account. However, my model or the number of posts a user can have in the database stored based on user ID found should be 25 posts. I'm guessing the following would work;
Model
class Post
belongs_to :user
validate :quota, :on => :refresh
def quota
Posts = Posts.find(params[:id])
if user.posts.count >= 25
flash[:error] = "Sorry you need to upgrade"
end
end
end
:refresh is something I'm working on where it grabs posts and adds these posts to the current_user within the database, or assigns the current_user id to each post it adds to the database.
am I correct on the above function? or should I add the validation count into my refresh controller/model like so;
class dashboard
def refresh
...
if self.user.posts.count >= 25
flash[:error] = "You've reached maximum posts you can import"
end
end
end
I would use a before_filter on the corresponding controller(s):
class PostsController < ApplicationController
before_filter :check_quota # you could add here: :only => [:index, :new]
private # optionnal
def check_quota
if user.posts.count >= 25
#quota_warning = "You've reached maximum posts you can import"
end
end
end
And in the view(s):
<% if #quota_warning.present? %>
<span><%= #quota_warning %></span>
<% end %>
Then add the validation on the model, to ensure the constraint:
class Post < ActiveRecord::Base
belongs_to :user
before_save :check_post_quota
private # optionnal
def check_post_quota
if self.user.posts.count >= 25
self.errors.add(:base, "You've reached maximum posts you can import")
return false
end
end
end
I want to merge two profiles into one. What is the best way to do this in Rails.
I have two profiles say user1 and user2 and there are at least 30 tables associated with them.
Now i want to merge them together so that there should be one profile say user1 and user2 should get deleted but all the associated data of user2 now should associate with user1.
For example: suppose user2 has two contacts and user1 has 3 contacts after merging user user1 should have 5 contacts.
Something like this
#user1 = User.find(1);
#user2 = User.find(2);
Contact.where("user_id = ?", #user2.id).update_all(:user_id => #user1.id)
#user2.destroy
in case of generalize solution
place file /lib/acts_as_user_merge.rb
module UserMerge
module ActsAsUserMerge
module Base
def self.included(klass)
klass.class_eval do
extend Config
end
end
end
module Config
def acts_as_user_merge
include ::UserMerge::ActsAsUserMerge::InstanceMethods
end
end
module InstanceMethods
def merge(user)
models = Array.new
models_names = User.reflections.collect{|a, b| b.class_name if b.macro==:has_many}.compact
models_names.each do |name|
models << Object.const_get name
end
models.each do |model|
model.where("user_id = ?", user.id).update_all(:user_id => self.id)
end
user.destroy
end
end
end
end
::ActiveRecord::Base.send :include, ::UserMerge::ActsAsUserMerge::Base
how to use
User < ActiveRecord::Base
has_many ...
acts_as_user_merge
end
#user1.merge(#user2)
kinda messy and not tested but should give you an idea
Something like that
def merge_users(dead, user)
User.reflections.each do |assoc, reflection|
foreign_key = reflection.foreign_key
case reflection.macro
when :has_many, :has_one then
unless reflection.options[:through]
reflection.klass.where(foreign_key => dead.id).update_all(foreign_key => user.id) # if id is a primary key
end
if options[:as] # polymorphic
if reflection.macro == :has_many
dead.send("#{options[:as].pluralize}")).each { |r| user.send("#{options[:as].pluralize}<<", r) }
else
user.send("#{options[:as]}=", dead.send("#{options[:as]}"))
user.save
end
end
when :belongs_to then
if options[:polymorphic]
user.send("#{assoc}=", deaf.send(assoc))
user.save
else
user.update_attribute(foreign_key, dead.send(foreign_key))
end
when :has_and_belongs_to_many then
dead.send("#{assoc}")).each { |r| user.send("#{assoc}<<", r) }
end
end
end
merge_users(dead_user, user)
dead_user.destroy
This article discusses this matter in depth, and provides the working code for it: http://ewout.name/2010/04/generic-deep-merge-for-activerecord/