I currently have a comment controller that has the method vote_up and vote_down this is how my vote_up currently works.
My Comment model has description and a count field.
def vote_up
#comment = Comment.find(params[:comment_id])
#comment.count += 1
if #comment.save
flash[:notice] = "Thank you for voting"
respond_to do |format|
format.html { redirect_to show_question_path(#comment.question) }
format.js
end
else
flash[:notice] = "Error Voting Please Try Again"
redirect_to show_question_path(#comment.question)
end
end
This allows for multiple vote up and downs. How would I design it so that a user can only vote once per comment but somehow keep track if they voted up or down, so they have the ability to change their vote if they want too.
You could do something like this. It prohibits identical votes but allows changing the vote to the opposite (it's a thumbs up/thumbs down system).
def vote(value, user) # this goes to your model
#find vote for this instance by the given user OR create a new one
vote = votes.where(:user_id => user).first || votes.build(:user_id => user)
if value == :for
vote_value = 1
elsif value == :against
vote_value = -1
end
if vote.value != vote_value
vote.value = vote_value
vote.save
end
end
migration:
def self.up
create_table :votes do |t|
t.references :comment, :null => false
t.references :user, :null => false
t.integer :value, :null => false
end
add_index :votes, :post_id
add_index :votes, :user_id
add_index :votes, [:post_id, :user_id], :unique => true
end
Alternatively, you could use a gem called thumbs_up or any other.
class AnswersController < ApplicationsController
def vote
#params[:answer_id][:vote]
#it can be "1" or "-1"
#answer = Answer.find(params[:answer_id])
#answer.vote!(params[:answer_id][:vote])
end
def show
#answer = Answer.find(params[:answer_id])
#answer.votes.total_sum
end
end
class Answer < ActiveRecord::Base
has_many :votes do
def total_sum
votes.sum(:vote)
end
end
def vote!(t)
self.votes.create(:vote => t.to_i)
end
end
class Vote < ActiveRecord::Base
belongs_to :answer
belongs_to :user
validates_uniqueness_of :user_id, :scope => :answer_id
end
you could perhaps add a validation in your model to make sure that count is numerically equal to or less than 1
validates :count, :numericality => { :less_than_or_equal_to => 1 }
Related
I want to create a polymorphic model to favorite each objects I want to create to stock in my user page.
I am developing a web app to learn japanese and we can favorite different types of cards as kanas or kanjis and sentences.
So there are 3 objects and soon more to favorite.
I migrated a table which names Favorite :
create_table "favorites", force: :cascade do |t|
t.integer "user_id"
t.integer "favoritable_id"
t.string "favoritable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here is the Favorite model belongs_to
class Favorite < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
belongs_to :user
end
Here are the Cards model has_many
class Symbole < ActiveRecord::Base
accepts_nested_attributes_for :kanji_attribute, :allow_destroy => true
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "symbole_id"
has_many :favorites, as: :favoritable
end
and I added in sentence model too
class Sentence < ActiveRecord::Base
include Authority::Abilities
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "sentence_id", dependent: :destroy
has_many :favorites, as: :favoritable
end
Now here is the Favorite controller and I don't really know how to write the create method. Here is the Controller I do:
class FavoritesController < ApplicationController
def index
#favorites = Favorite.where(user: current_user)
end
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = current_user.favoritable.favorites.create(symbole: #symbole, sentence: #sentence).first
if #favorite.present?
#favorite.destroy
else
#favorite = current_user.favorites.new(symbole: #symbole, sentence: #sentence)
if not #symbole.favorites.where(user: current_user).take
#sentence.favorites.where(user: current_user).take
#favorite.save
end
end
# redirect_to favs_path
# redirect_to :back
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
def destroy
#favorite = Favorite.find(params[:id])
#favorite.destroy
redirect_to :back
end
end
Please could someone give me the right way to favorite all object I want and add in an favorite index#view.
Thank you for your help.
I think my question is simple but no. How to favorite each object I want with the def Create controller what is the best method?
I do that
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = #favoritable.favorites.build(favorite_params)
#favorite.user = current_user
#favorite.save
respond_to do |format|
format.js { render :ajax_update_favorites }
end
end
Not sure I understood the problem entirely. It looks like you're overcomplicating favoritesController#create. If a record only should be favorited once, you should add a uniqueness validation in the Favorite model.
Assuming that you have your user model set up like
class User < ActiveRecord::Base
has_many :favorites
# Rest..
end
def create
#favorite = current_user.favorites.create(favorite_params)
# This will create a new Favorite with user_id: current_user.id, favoritable_type: "Symbole", favoritable_id: 1337
# Is this the desired behaviour?
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
private
def favorite_params
params.require(:favorite).permit(:favoritable_type, :favoritable_id)
end
If this is called from javascript with jquery pass the type and id that you wan't to favorite.
$.post( "/favorites", {
favorites: {
favoritable_type: "Symbole",
favoritable_id: 1337
}
});
I'm (very) new to ror and have read many tutorials for this issue but none seem to work. I'm trying to let one user create one booth to sell things.
This is my db migration:
class CreateBooths < ActiveRecord::Migration
def change
create_table :booths do |t|
t.string :name
t.references :user, index: true
t.timestamps null: false
end
add_index :booths, [:user_id]
end
end
Here is the booth controller:
class BoothsController < ApplicationController
before_action :logged_in_user
def new
#booth = Booth.new
end
def create
#booth = current_user.booths.build(booth_params)
if #booth.save
flash[:success] = "Congrats on opening your booth!"
redirect_to root_url
else
render 'new'
end
end
private
def booth_params
params.require(:booth).permit(:name)
end
end
And this is the booth model:
class Booth < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
I also added this to the user model:
has_one :booth, dependent: :destroy
When I include validates :user_id, presence: true it won't save to the db. When I exclude it, it saves but does not include a user id in the database. If you are still reading thank you and I hope you can help!
You need to change create method of your BoothsController to this:
def create
#booth = current_user.build_booth(booth_params)
if #booth.save
flash[:success] = "Congrats on opening your booth!"
redirect_to root_url
else
render 'new'
end
end
Here, you have one-to-one association between user and booth, and that's why you have to instantiate booth for current_user using build_<singular_association_name>, which is build_booth and pass params to it: build_booth(booth_params).
booths.build(booth_params) works for one-to-many association, for example: user has many booths, not vice a versa.
I have a form for a model called isp, which 'has_many' isp accounts. the isp account belongs to to 'isp'.
There is a validation on the isp_account that means it cant be added if there isnt an isp_id, so my reasoning is to created a nested form. I created the nested form like so
= simple_form_for #isp, :html => { :multipart => true } do |f|
= f.input :title
= f.simple_fields_for :isp_accounts do |tag|
= tag.input :title, label: "Tag Name"
however the nested attribute isnt being displayed. There are no errors etc. Why is this? Am I approaching this in the best way? is this the only way?
here's the code
ISP MODEL
class Isp < ActiveRecord::Base
has_many :isp_accounts, dependent: :destroy
has_many :deployments, through: :servers
has_many :servers, through: :isp_accounts
validates :title, presence: true
accepts_nested_attributes_for :isp_accounts
end
ISP ACCOUNTS MODEL
class IspAccount < ActiveRecord::Base
belongs_to :isp
has_many :deployments, through: :servers
has_many :servers, dependent: :destroy
validates :title, presence: true
validate :check_associates
private
def check_associates
associated_object_exists Isp, :isp_id
end
end
ISP ACCOUNT CONTROLLER
....
def new
#isp_account = IspAccount.new
end
def update
#isp_account.update_attributes(isp_accounts_path)
if #isp_account.save
record_saved
return redirect_to(isp_accounts_path)
else
check_for_errors
return render('/isp_accounts/edit')
end
end
private
def get_isp_accounts
#isp_account = IspAccount.all
end
def get_isp_account
#isp_account = IspAccount.find(params_isp_accounts)
end
def params_isp_accounts
params.require(:isp_account).permit!
end
end
....
def new
#isp = Isp.new
end
def update
#isp.update_attributes(params_isp)
if #isp.save
record_saved
return redirect_to(isps_path)
else
check_for_errors
return render('new')
end
end
private
def params_isp
params.require(:isp).permit(:title, isp_accounts_attributes: [:id, :title])
end
def get_isp
#isp = Isp.where(id: params[:id]).first
unless #isp
record_not_found
return redirect_to(isps_path)
end
end
def get_isps
#isp = Isp.all.order(:title)
end
end
SCHEMA
create_table "isp_accounts", force: true do |t|
t.string "title"
t.integer "isp_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "isps", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
ok i got it. I was missing the new bit for that attribute in my controller. pretty basic really.
def new
#isp = Isp.new
#isp.isp_accounts.new
end
Currently I allow users to follow one another on my rails app (similar to twitter).
I would love if New Users that sign up to the site Automatically follow Admin User.
Similar to how MySpace use to automatically make Tom your first friend
Below is the code I use to create new users and allow users to follow one another.(i know this is a very broad question but .....)
(Can someone please point me in the right direction onto how I can get this started. Would I need to create a method....in my models or add code to the controller?)
New to Rails Please help)... :)
USER CONTROLLER
class UsersController < ApplicationController
before_filter :admin_user, only: [:destroy]
respond_to :html, :js
def new
#user = RegularUser.new
end
def index
#users = User.paginate(page: params[:page], :per_page => 100).search(params[:search])
end
def destroy
User.find_by_username(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_url
end
def create
#user = RegularUser.new(params[:regular_user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
UserMailer.welcome_user(#user).deliver
sign_in #user
flash[:success] = "Welcome to the ClickOnComics!"
redirect_to (publishers_path)
else
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def follow_admins
admins = User.find_by_admin(true)
admins.each do |admin|
self.follow!(admin)
end
end
class RelationshipsController < ApplicationController
before_filter :current_user
respond_to :html, :js
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_with #user
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_with #user
end
end
MODELS
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
after_create :follow_admins
def follow_admins
admins = User.find_all_by_admin(true)
admins.each do |admin|
self.follow!(admin)
end
end
def following?(other_user)
relationships.find_by_followed_id(other_user.id)
end
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
end
def unfollow!(other_user)
relationships.find_by_followed_id(other_user.id).destroy
end
end
I used this tutorial to help me establish privileged administrative users with a boolean admin attribute in the User model
http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-users#sec-administrative_users
SCHEMA
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.string "role"
t.string "username"
t.timestamp "created_at", :null => false
t.timestamp "updated_at", :null => false
t.boolean "admin", :default => false
t.string "password_reset_token"
t.timestamp "password_reset_sent_at"
end
Would I need to create a Method that defines user_admin?
In user.rb add a after_create filter
after_create :follow_admin!
def follow_admin!
relationships.create!(followed_id: admin_user.id)
end
In create action before sign_in add
#user.follow! admin_user
you need to fetch admin user first somehow.
Good idea would be to make follow!, following? and unfollow! methods to accept either id or object as in
def follow!(user_or_id)
id = (user_or_id.is_a?(User) ? user_or_id.id : user_or_id)
relationships.create!(followed_id: id)
end
Essentially:
I want to set the title of a revision to the title of the post it is a revision of.
I want to set the revision_id to the id if the new post is not a revision (or is_revision = false)
So far, I'm having a lot of trouble with this. Any help appreciated.
post.rb
class Post < ActiveRecord::Base
has_many :revisions, class_name: "Post", foreign_key: "revision_id"
belongs_to :revision, class_name: "Post"
#...
before_save :post_title
def post_title
if :is_revision == false
#revision_id = #post_id
elsif :is_revision == true
:revision_id != :post_id
#title = #revision.title
end
end
#...
end
Update
I am now able to get this working through the controller. Should I still aim to make this work occur in the model? The same code is under create and update actions.
posts_controller.rb
def create
#post = current_user.posts.new(params[:post])
if #post.save
if #post.is_revision == false
#post.revision_id = #post.id
#post.save
elsif #post.is_revision == true
#post.title = #post.revision.title
#post.save
end
end
end
I don't quite understand your logic there, maybe you should tell us some context.
Otherwise, did you simply try:
class Post < ActiveRecord::Base
has_many :revisions, class_name: "Post", foreign_key: "revision_id"
belongs_to :revision, class_name: "Post"
#...
before_save :set_title_to_revision_title, :if => :is_revision?
# Need to be called after the save because post.id will not be available on the create
after_save :update_revision_id_to_id, :unless => :is_revision?
def is_revision?
#is_revision
end
def set_title_to_revision_title
#title = #revision.title
end
def update_revision_id_to_id
# just make a quick call to update it i
update_attribute :revision_id, #id
end
#...
end