Adding button click counter in rails 3 - model-view-controller

I want to add buttons on my article so that I can know the number of times its clicked and update counter on the database, I am using mongoid ,my model is:
class Article
include Mongoid::Document
include Mongoid::Timestamps
field :title, :type => String
field :content, :type => String
field :likes, :type => Integer ,:default => 0
field :dislikes, :type =>Integer, :default => 0
field :spam, :type => Integer, :default => 0
end
My articles show controller is:
def show
#article = Article.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #article }
end
end
My View for show is:
<p id="notice"><%= notice %></p>
<p>
<b>Title:</b>
<%= #article.title %>
</p>
<p>
<b>Content:</b>
<%= raw #article.content %>
</p>
Likes : <%= #article.likes %> <br/>
Dislikes : <%= #article.dislikes %><br/>
Spams : <%= #article.spam %><br/>
<%= link_to 'Edit', edit_article_path(#article) %> |
<%= link_to 'Back', articles_path %>
I find anything about it in internet.
How can I achieve it?

The easiest thing to do would be add a click_count integer attribute to your Article model and then increment this in your controller code:
def show
#article = Article.find(params[:id])
#article.increment! :click_count
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #article }
end
end

i got it done, phew!
I added the following form in my show.html.erb:
<%=form_for(#article,:action=>"update") do |f| %>
<%= submit_tag "Like", :name=>"like"%>
<%= submit_tag "Dislike",:name=>"dislike"%>
<%= submit_tag "Spam",:name=>"spam" %>
<%end%>
and wrote the following update controller:
def update
#article=Article.find(params[:id])
if params[:like]
#article.likes=#article.likes+1
elsif params[:dislike]
#article.dislikes=#article.dislikes+1
elsif params[:spam]
#article.spams=#article.spams+1
end
respond_to do |format|
if #article.update_attributes(params[:article])
format.html {redirect_to #article, :notice => "Article Updated"}
else
format.html {render :action=>"edit", :notice=> "Unable to update Article , sorry! :("}
end
end
end
It worked like a charm.

Related

Active Record Association not saving in database

I have two models:
class Tool < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :tools, dependent: :destroy
end
And I created a migration to provide the foreign key of the model:
class AddUserIdToTool < ActiveRecord::Migration
def change
add_column :tools, :user_id, :integer
end
end
I have the following form:
<%= form_for #tool, :html => { :multipart => true } do |f| %>
<% if #tool.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tool.errors.count, "error") %> prohibited this tool from being saved:</h2>
<ul>
<% #tool.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.file_field :tool_image %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Whenever I submit the form the foreign key is not updated(user_id). I see the following while in my console:
irb(main):002:0> Tool.last
Tool Load (0.0ms) SELECT "tools".* FROM "tools" ORDER BY "tools"."id" DESC LIMIT 1
=> #<Tool id: 6, name: "wrench2", description: "another wrench", created_at: "2015-04-09 21:38:47", updated_at: "2015-04
-09 21:38:47", tool_image_file_name: "wrench.jpg", tool_image_content_type: "image/jpeg", tool_image_file_size: 3424, to
ol_image_updated_at: "2015-04-09 21:38:43", user_id: nil>
irb(main):003:0>
As you can see the user_id is nil
Here is my controller:
class ToolsController < ApplicationController
before_action :authenticate_user!, only: [:new, :destroy, :edit, :update], notice: 'you must sign in first!'
before_action :set_tool, only: [:show, :edit, :update, :destroy]
# GET /tools
# GET /tools.json
def index
#tools = Tool.all
end
# GET /tools/1
# GET /tools/1.json
def show
end
# GET /tools/new
def new
#tool = Tool.new
end
# GET /tools/1/edit
def edit
end
# POST /tools
# POST /tools.json
def create
#tool = Tool.new(tool_params)
respond_to do |format|
if #tool.save
format.html { redirect_to #tool, notice: 'Tool was successfully created.' }
format.json { render :show, status: :created, location: #tool }
else
format.html { render :new }
format.json { render json: #tool.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tools/1
# PATCH/PUT /tools/1.json
def update
respond_to do |format|
if #tool.update(tool_params)
format.html { redirect_to #tool, notice: 'Tool was successfully updated.' }
format.json { render :show, status: :ok, location: #tool }
else
format.html { render :edit }
format.json { render json: #tool.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tools/1
# DELETE /tools/1.json
def destroy
#tool.destroy
respond_to do |format|
format.html { redirect_to tools_url, notice: 'Tool was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_tool
#tool = Tool.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def tool_params
params.require(:tool).permit(:name, :description, :tool_image, :user_id)
end
end
How would I get the user_id updated with the id of the logged in user? Do I have to include a hidden field in my form or something like that?
Also do I have to permit the user_id variable within my strong parameters in my controller? I have tried this but it has not solved the problem...
How does this work?
Currently you are building a tool on its own. To associate it with the user model you need to create a tool model in the following way:
#user.tools.build
It will create a new ActiveRecord tool model with proper user_id of a belonged model. But to get parent you need to fetch its id from your params. It could be done in a such way, in your action:
#user = User.find(params[:user_id])
Note: to make it possible your routes should be nested correspondingly (read more here: http://guides.rubyonrails.org/routing.html)
So, all in all, your new action should look like:
def new
#user = User.find(params[:user_id])
#tool = #user.tools.build
end
And in your routes.rb
resources :users do
resources :tools
end

How to solve undefined method `permit' for :user:Symbol error in ror-4

Please help me to solve this error.When update action is executing this error is showing.
Error:
NoMethodError in UsersController#update
undefined method `permit' for :user:Symbol
My code snippets are given below.
views/users/edit.html.erb
<h1>Edit your data</h1>
<%= form_for #user,:url => {:action => 'update',:id => params[:id]} do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field:name,:value => #edit.name %>
<%= f.email_field:email,:value => #edit.email %>
<%= f.text_field:message,:value => #edit.message %>
<%= f.submit "Update" %>
<% end %>
<%= link_to "Back",users_index_path %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_params)
if #user.save
flash[:notice]="Your data is saved succesfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You are entering wrong data"
flash[:color]="invalid"
render :new
end
end
def show
#user=User.all
end
def delete
#user=User.find(params[:id])
if #user.delete
flash[:notice]=#user.name+"has deleted successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]=#user.name+"could not delete.Please check it.."
flash[:color]="invalid"
render :show
end
end
def edit
#edit=User.find(params[:id])
#user=User.new
end
def update
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data has updated successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..check it.."
flash[:color]="invalid"
render :edit
end
end
private
def users_params
params.require(:user).permit(:name, :email, :message,pets_attributes: [:name, :email,:message])
end
def update_params
params.require (:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
end
model/user.rb
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true,:length => { :minimum => 5 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :message, :presence => true
end
Please help me to solve the above error.
You have space between require and (:user). Your current code is equivalent to:
def update_params
params.require(:user.permit(:name,:email,:message,pets_attributes: [:name, :email,:message]))
end
As you can see now, you call permit method on :user symbol and this is direct cause of error.
It should be:
def update_params
params.require(:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
BTW having two methods that do exactly same thing is quite pointless.
Check your question:
you have a space after require and before (:user)
Try:
def update_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
For a better way, you can have just one method:
def user_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
Instead of having separate filter methods for new and edit, you can have just one method and reuse that in both new and edit.
Just keep things Simply DRY.

Routing error in activerecord reputation gem in rails 4

Hello I'm new to rails 4
I am working on project where we can post and rate it. I have used activerecord reputation gem. I have been following the http://railscasts.com/episodes/364-active-record-reputation-system video.
I am stuck at the routing point. When I click on upvote or downvote it shows me error.
my routes.rb file has
resources :posts do
resources :comments, :only => [:create]
member { post :vote }
end
get "posts/create"
get "posts/destroy"
get "posts/new"
get "posts/index"
get "posts/show"
get "posts/edit"
get "posts/update"
_post.html.erb
<h4 class="timeline-title"><%= link_to_unless_current post.title, post %></h4>
<p> Created : <%= post.created_at.strftime("%d/%m/%Y") %> by <%= post.postedby %>
</p>
<% if current_cubestudent.email == post.postedby %>
<p><%= link_to 'Edit', edit_post_path(#post) %>
<%= link_to 'Destroy', posts_path, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
<%= simple_format post.body , :class => "timeline-body"%>
<%= pluralize post.reputation_for( :votes).to_i, "vote" %>
<% if current_cubestudent && !current_cubestudent.voted_for?(post) %>
<%= link_to "up", vote_post_path(post, type: "up"), method: "post" %>
<%= link_to "down", vote_post_path(post, type: "down"), method: "post" %>
<% end %>
my post#show is
<%= stylesheet_link_tag "application",:media =>"screen" %>
<p id="notice"><%= notice %></p>
<p id="alert"><%= alert %></p>
<%= render :partial => #post %>
<%= link_to 'Back', posts_path %>
<h2 id="timeline">Comments</h2>
<div>
<%= render :partial => #post.comments %>
</div>
<div class="container">
<%= form_for [#post, Comment.new] do |f| %>
<div style="padding-bottom:0">
<%= f.text_area :body , :placeholder => "Write your comment"%>
<%= f.submit "Add comment", :class => "btn btn-info" %>
</div>
<% end %>
</div>
posts controller is
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def create
#post = Post.new(post_params)
#post.postedby = current_cubestudent.email
#post.postedbyid = current_cubestudent.id
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
def new
#post = Post.new
end
def index
#posts = Post.find_with_reputation(:votes, :all, order: "votes desc")
end
def show
#post = Post.find(params[:id])
end
def edit
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def vote
value = params[:type] == "up" ? 1 : -1
#post = Post.find(params[:id])
#post.add_or_update_evaluation(:votes, value, current_cubestudent)
redirect_to :back, notice: "Thank you for voting"
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :body, :subject)
end
end
after rake routes | grep post
C:\Sites\project>rake routes | grep post
post_comments POST /posts/:post_id/comments(.:form comments#create
vote_post POST /posts/:id/vote(.:format) posts#vote
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
posts_create GET /posts/create(.:format) posts#create
posts_destroy GET /posts/destroy(.:format) posts#destroy
posts_new GET /posts/new(.:format) posts#new
posts_index GET /posts/index(.:format) posts#index
posts_show GET /posts/show(.:format) posts#show
posts_edit GET /posts/edit(.:format) posts#edit
posts_update GET /posts/update(.:format) posts#update
Can someone help me on it....??
Your main problem is in this code
<%= link_to "up", vote_post_path(post, type: "up"), method: "post" %>
you would like to send "post" request but in fact you send default ("get") request.
I can suppose that link_to accepts only symbols for method (you pass string). So try this
<%= link_to "up", vote_post_path(post, type: "up"), method: :post %>
Another source of the problem can be wrong routes. If code above does not help you run in console rake routes | grep post and add output to the question.

Rails form_for own action routes

I want to modify the action (submit) for a form_for helper
<%= form_for(#rating, :as => :post, :url => demo_create_rating_path(#rating)) do |f| %>
<div class="field">
<%= f.label :value %><br />
<%= f.select :value, %w(1 2 3 4 5) %>
</div>
<%= f.hidden_field :article_id, :value => #article.id%>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description, size: "100x5" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is my View and it does not work.
All I want is, that I can redirekt the Action after submit button but then a get this error:
ActionController::RoutingError (No route matches {:controller=>"demo_ratings", :action=>"create", :article_id=>#<Rating id: nil, value: nil, description: nil, article_id: nil, user_id: nil, created_at: nil, updated_at: nil>}):
app/views/demo_ratings/_form.html.erb:1:in `_app_views_demo_ratings__form_html_erb__1912848844925280312_70155649546120'
app/views/demo_ratings/new.html.erb:13:in `_app_views_demo_ratings_new_html_erb__27525029454473720_70155632487040'
What am I doing wrong?
UPDATE
All my funktion that are need by form_for helper:
def new
#rating = Rating.new
#article = Article.find(params[:article_id])
end
def edit
#rating = Rating.find(params[:id])
#article = Article.find(params[:article_id])
end
def create
#rating = Rating.new(params[:rating])
if #rating.save
#article= Article.find(params[:article_id])
puts #article.name
puts #rating.id
#rating.article = #article
puts #rating.article.name
redirect_to demo_rating_path(#rating, :article_id => #article.id), notice: 'Rating was successfully created.'
else
render action: "new"
end
end
def update
#rating = Rating.find(params[:id])
if #rating.update_attributes(params[:rating])
#article = #rating.article
redirect_to demo_rating_path(#rating), notice: 'Rating was successfully updated.'
else
render action: "edit"
end
end
Try this:
<%= form_for(#rating, :as => :post, :url => demo_create_rating_path) do |f| %>
The #rating in the url is providing a nil object id, and you don't have an id yet.
If you want to share the form between create and update, then use the following:
<% form_for(#rating, :as => :post) do |f| %>
For reference, review the output of a rails generated scaffold's _form.html.erb.
In your controller, your are saving the new/ updated record before your processing. The statement if #rating.save should come after #rating.article = #article.
def create
#rating = Rating.new(params[:post])
#article= Article.find(params[:article_id])
#rating.article_id = #article.id
if #rating.save
redirect_to demo_rating_path(#rating, :article_id => #article.id), notice: 'Rating was successfully created.'
else
render action: "new"
end
end

has_one :through - build_association undefined?

I have a Section model, where a Section can be a parent of another Section (subsection).
Here is my model:
class Section < ActiveRecord::Base
has_many :exercises
has_one :parent_link,
:foreign_key => 'subsection_id',
:class_name => 'SectionLink',
:dependent => :destroy
has_one :parent, :through => :parent_link
has_many :subsection_links,
:foreign_key => 'parent_id',
:class_name => 'SectionLink',
:dependent => :destroy
has_many :subsections, :through => :subsection_links
attr_accessor :parent_id
def to_param
"#{id}-#{description.parameterize}"
end
def self.search(search)
if search
find(:all, :conditions => ['description LIKE ?', "%#{search}%"])
else
find(:all)
end
end
end
And the association model:
class SectionLink < ActiveRecord::Base
belongs_to :parent, :class_name => 'Section'
belongs_to :subsection, :class_name => 'Section'
end
My controller:
class SectionsController < ApplicationController
# GET /sections
# GET /sections.json
def index
#sections = Section.order("subsections_count DESC").search(params[:search])
respond_to do |format|
format.html # index.html.erb
end
end
# GET /sections/1
# GET /sections/1.json
def show
#section = Section.find(params[:id])
#subsections = #section.subsections
#exercises = #section.exercises
respond_to do |format|
format.html # show.html.erb
format.json { render json: #section }
end
end
# GET /sections/new
# GET /sections/new.json
def new
#section = Section.new
#section.parent_id = params[:parent]
respond_to do |format|
format.html # new.html.erb
format.json { render json: #section }
end
end
# GET /sections/1/edit
def edit
#section = Section.find(params[:id])
end
# POST /sections
# POST /sections.json
def create
#section = Section.new(params[:section])
#parent = #section.build_parent(:parent_id => #section.parent_id) unless #section.parent_id.empty?
respond_to do |format|
if #section.save
format.html { redirect_to #section, notice: 'Section was successfully created.' }
format.json { render json: #section, status: :created, location: #section }
else
format.html { render action: "new" }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# PUT /sections/1
# PUT /sections/1.json
def update
#section = Section.find(params[:id])
respond_to do |format|
if #section.update_attributes(params[:section])
format.html { redirect_to #section, notice: 'Section was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #section.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sections/1
# DELETE /sections/1.json
def destroy
#section = Section.find(params[:id])
#section.destroy
respond_to do |format|
format.html { redirect_to sections_url }
format.json { head :no_content }
end
end
end
The parent ID is fed in via a hidden field in the form:
<%= form_for(#section) do |f| %>
<% if #section.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#section.errors.count, "error") %> prohibited this section from being saved:</h2>
<ul>
<% #section.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<%= f.hidden_field :parent_id, :value => #section.parent_id %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'm getting
undefined method 'build_parent' for #<Section:0xb4f1764c>
Is there a better way of modelling this association? Why is build_parent undefined?
UPDATE:
Now works with following controller code:
#section = Section.new(params[:section])
unless #section.parent_id.empty?
#parent = Section.find(#section.parent_id)
#section.parent = #parent
end
Looking for any suggestions on how it can be improved, and why it did not work before...
You're looking to do a self join.
class Section < ActiveRecord::Base
has_many :subsections, :class_name => "Section"
belongs_to :parent_section, :class_name => "Section",
:foreign_key => "parent_id"
end

Resources