How can I add custom vote buttons to a rails app - ruby-on-rails

So here is an idea
class Question < ActiveRecord::Base
has_many : answers
end
class Answer < ActiveRecord::Base
belongs_to :question
has_one :vote
end
class Vote < ActiveRecord::Base
belongs_to :question
end
How can i limit the number of questions a user can ask?
Is there a better way of this?

Answer to the first question:
Inside of the QuestionsController create method, you should just put some code that says something like:
if user.questions.length > 3
#tell them they can't ask more questions
else
#create the question
end
to the second:
Also, I don't think it makes sense to have Vote be it's own resource. I would just define 'vote' or 'votes' as a field on Answer. When an answer gets voted for, you just increment Answer.votes. Depends on your use case though

Beyond, if you want to customize more in depth your validation, you can delegate the validation as so, assuming the user_id is the user column nested in the question model
class Question < ActiveRecord::Base
validates_with LengthValidator, :field => :user_id
....
end
class LengthValidator < ActiveModel::Validator
def validate(record)
if options[:fields].any?
#put the above conditional of #Accipheran
end
end

Related

Rails - Querying Noticed Notification with the params id

I have searched through the related questions for example this one and the solutions marked there doesn't work for me.
So here is my problem:
I want to get a list of notifications that are for a specific recipient, and the notifications have to be made on comments belonging to a specific plant.
Currently I am using ruby to filter but the database hit is not ideal.
Here is the state of my code.
Models:
class Plant < ApplicationRecord
has_many :comments
end
class User < ApplicationRecord
has_many :notifications, as: :recipient, dependent: :destroy
end
class Notification < ApplicationRecord
belongs_to :recipient, polymorphic: true
end
class Comment < ApplicationRecord
has_noticed_notifications
end
class CommentNotification < Noticed::Base
def comment
params[:comment]
end
end
This is the query I am currently using: #plant.comments.flat_map { |comment| comment.notifications_as_comment }.filter { |notification| notification.recipient == current_user }.map(&:mark_as_read!)
Any help is deeply appreciated...
I resolved this by making a comment method and then using that in my filter, it also killed all the excess dB hits I was getting.
def comment_id
self[:params][:comment].id
end
Then I used this query to arrive at the result, looks cleaner too. Note comment_ids = #plant.comments.ids
Notification.unread.where(recipient_id: current_user.id)
.filter { |notification| comment_ids.include?(notification.comment_id) }
.map(&:mark_as_read!)
Noticed has a built in helper method for finding notifications based on the params.
If you add has_noticed_notifications to the model which you want to search for in the params, Comment in your case.
You can then call #comment.notifications_as_comment and it will return all notifications where the #comment is params[:comment]
This is in the Noticed readme here. I definitely came here and found this question before I found the details in the readme!

Simpler way to update big decimal column in rails?

I am building a simple budgeting app, and have a line of code that feels convoluted and overly complex. For context:
class User < ActiveRecord::Base
has_one :month_budget
has_many :expenditures, as: :spendable
end
class MonthBudget < ActiveRecord::Base
belongs_to :user
has_many :expenditures, as: spendable
end
class Expenditure < ActiveRecord::Base
belongs_to :spendable, polymorphic: true
end
Within my Expenditure class, I have defined a class method, add_expenditure:
class Expenditure < ActiveRecord::Base
def self.add_expenditure(user, params) #params passed will be in [:expenditure][*keys], in which possible keys are [:amount] or [:location]
if user.month_budget
user.month_budget.expenditures.create(params)
new_amount = user.month_budget.current_amount += params[:amount].to_d
user.month_budget.update(current_amount: new_amount)
end
end
end
Is there a more efficient way to add a value to the initial month_budget.current_amount column, and then record this new number to the database?
Cheers in advance!
Maybe you could try increment! method (http://apidock.com/rails/v4.2.1/ActiveRecord/Persistence/increment%21).
However, I am not sure if it works well with big decimals.
class Expenditure < ActiveRecord::Base
def self.add_expenditure(user, params)
if user.month_budget
user.month_budget.expenditures.create(params)
user.month_budget.increment!(:current_amount, params[:amount].to_d)
end
end
end

How to call instance method of comment class through Article Model ?

class Comment < ActiveRecord::Base
belongs_to :article
end
class Article < ActiveRecord::Base
has_many :comments do
def posted_comments
#user_comment is just an attribute of comment.
collect(&:user_comment)
end
end
end
to fetch the posted comments :
Article.first.comments.posted_comments
=> ["Nice article posted", "comment 2 added", "Good article"]
Above one is fetching correct results, but I want to have a more compact version.
Something like this:
Article.first.posted_comments
#this should list the collection of comments on the article.
Can we do something like this with Rails ActiveRecord ?
For simply solution, you can define method called posted_comments that calls nested association as the following:
def posted_commments
self.comments.posted_comments
end
Or, Try the following code:
has_many :posted_comments, -> { select("user_comment") }, class_name: "Comment"

ActiveRecord attribute depends of a calculation of other model

This is my scenario:
class User < ActiveRecord::Base
has_many :things
# attr_accessible :average_rating
end
class Thing < ActiveRecord::Base
belongs_to :user
has_one :thing_rating
end
class ThingRating < ActiveRecord::Base
belongs_to :thing
attr_accessible :rating
end
I want to have an attribute in my User model which has the average calculation of his related ThingsRating.
What would be the best practice to manage this?
Thanks
May be you can use relation not sure but you can try this
class User < ActiveRecord::Base
has_many :things
has_many :thing_ratings, through: :things
# attr_accessible :average_rating
def avg_rating
#avg_rating ||= thing_ratings.average("thing_ratings.rating")
end
end
The easy way :
class User < ActiveRecord::Base
has_many :things
def avg_rating
#avg_rating ||= average(things.map(&:thing_rating))
end
private
def average(values)
values.inject(0.0) { |sum, el| sum + el } / arr.size
end
end
This is fine as a starter. But if you have a bit of trafic, you might find yourself with scaling problems.
You'll then have to refactor this to avoid making an SQL query to the things every time you call the method for a different user.
You could then have several possibilites :
Add a field in your User database, avg_rating, which would be updated by the ThingRating when it's created or updated.
Use a memcached or redis database to cache the value and invalidate the cache every time a ThingRating is updated or created.
These solutions aren't exhaustive of course. And you could find other ones which would better fit your needs.

What is the most elegant way to validate the presence of ONLY one out of two attributes using Rails?

class Followup < ActiveRecord::Base
belongs_to :post
belongs_to :comment
end
This model needs to only have either a post or a comment, but only one of the two.
Here's the rspec for what I'm trying to do:
it "should be impossible to have both a comment and a post" do
followup = Followup.make
followup.comment = Comment.make
followup.should be_valid
followup.post = Post.make
followup.should_not be_valid
end
I can see a bunch of solution to do this, but what would be the most elegant way of doing this?
I think what you really want is a polymorphic association.
Ryan does a great job explaining them in Railscast #154.
class Followup < ActiveRecord::Base
belongs_to :followupable, :polymorphic => true
end
class Post < ActiveRecord::Base
has_many :followups, :as => :followupable
end
class Comment < ActiveRecord::Base
has_many :followups, :as => :followupable
end
The question of elegance is of course subjective but the following example will do exactly what you want, including separate error messages for the 2 invalid conditions i.e both values provided and no values provided.
class Foo < ActiveRecord::Base
validate :one_and_only_one
def one_and_only_one()
errors.add_to_base("You must provide either a foo or a bar")
if self.foo.blank? && self.bar.blank?
errors.add_to_base("You cannot provide both a foo and a bar")
if !self.foo.blank? && !self.bar.blank?
end
end
EDIT
Thinking of more solutions then this might pass the elegance test better
errors.add_to_base("You must provide either a foo or a bar")
unless [f.foo, f.bar].compact.length == 1
Although this will fail on space filled fields.

Resources