I want to allow users to vote on posts without signing up, and have the vote instead tied to their ip address. I tried following this post but I need some more clarification. this is the error im getting from the posts_controller
undefined method `find_or_create_by_ip' for #
This is my code so far:
posts_controller:
def upvote
#post = Post.find (params[:id])
session[:voting_id] = request.remote_ip
upvote = session.find_or_create_by_ip(session[:voting_id])
#post.upvote
redirect_to :back
end
def downvote
#post = Post.find (params[:id])
session[:voting_id] = request.remote_ip
downvote = session.find_or_create_by_ip(session[:voting_id])
#post.downvote
redirect_to :back
end
session model:
class session < ActiveRecord::Base
acts_as_voter
request.remote_ip
end
routes.rb:
Rails.application.routes.draw do
get 'static_pages/home'
get 'static_pages/about'
resources :posts do
member do
put "like" , to: "posts#upvote"
put "dislike" , to: "posts#downvote"
end
end
In the other post someone said add an ip column to the sessions table. What exactly does that mean? I also saw somewhere that I would need to create a db table as well. do I? and how would I do that? Sorry about having to post this, put Im pretty new to this, so it would be great if it was spelled out better for me. Thanks!
If you are using Rails 4+ dynamic finders have been deprecated and extracted to a gem. The standard is now find_or_create_by or find_or_initialize_by.
def upvote
#post = Post.find (params[:id])
session[:voting_id] = request.remote_ip
upvote = Session.find_or_create_by(ip: session[:voting_id])
#post.upvote
redirect_to :back
end
def downvote
#post = Post.find (params[:id])
session[:voting_id] = request.remote_ip
downvote = Session.find_or_create_by(ip: session[:voting_id])
#post.downvote
redirect_to :back
end
class Session < ActiveRecord::Base
acts_as_voter
request.remote_ip
end
Related
I'm writing a simple website in which users (authenticated with Devise) can create posts. Upon creating a new post, I'm running into this error in which it won't redirect to the post. Here's my Posts controller:
class PostsController < ApplicationController
before_filter :authenticate_user!
def new
#post = current_user.posts.new
end
def create
#post = current_user.posts.new(post_params)
if #post.save
redirect_to #post
end
end
def show
#post = Post.find_by_id(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
Here's my routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :users do
resources :posts
end
root 'posts#new'
end
Since the posts resource is nested within users I thought perhaps I should have this in my controller:
if #post.save
redirect_to current_user.#post
end
But that produces a SyntaxError in PostsController#create error.
Can anyone see the problem that's preventing the controller from redirecting to the post after it's created? Any help would be much appreciated.
Try this -
redirect_to [current_user,#post]
OR,
redirect_to user_post_path(current_user, #post)
hope it helps!
In your model, have you allowed for nested attributes? In the controller you want to use build instead of new.
I'm in the process of creating a website similar to Reddit. I would like to allow a moderator to be able to update a topic, but not be able to create or delete topic. I'm aware that I need to update TopicsController but I'm not sure how. My main problem is that I'm not sure how to make the code specific enough to ensure that a moderator can only update; not delete or create a topic, as an admin can.
My current code looks like this:
class PostsController < ApplicationController
before_action :require_sign_in, except: :show
before_action :authorize_user, except: [:show, :new, :create]
def show
#post = Post.find(params[:id])
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
end
def create
#post.body = params[:post][:body]
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.build(post_params)
#post.user= current_user
if #post.save
flash[:notice] = "Post was saved"
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post.assign_attributes(post_params)
if #post.save
flash[:notice] = "Post was updated."
redirect_to [#post.topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :edit
end
end
def destroy
#post = Post.find(params[:id])
if #post.destroy
flash[:notice] = "\"#{#post.title}\" was deleted successfully."
redirect_to #post.topic
else
flash[:error] = "There was an error deleting the post."
render :show
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def authorize_user
post = Post.find(params[:id])
unless current_user == post.user || current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to [post.topic, post]
end
end
end
I've already added a moderator role to the enum role.
I apologise if this seems really basic...but it has got me stumped!
Thanks in advance!
I could answer with some custom solution, but it's better to use a more structured and community-reviewed approach: authorization with cancan.
As tompave noticed you can use cancan gem for this.
Personally I prefer pundit.
In old days I used to define permissions directly in code everywhere: in controllers, in views and even models. But it's really bad practice. When your app grows, you are lost: you update a view, but you should make the same change in controller and sometimes in model too. It soon becomes absolutely unmanageable and you have no idea what your users can and cannot do.
Pundit, on the other hand, offers central place -- policy -- for defining what user can do. Views and controllers can then use those policies.
For example, if you need to define Post's policy you simply create app/policies/post_policy.rb file:
class PostPolicy
attr_reader :user
attr_reader :post
def initialize(user, post)
#user = user
#post = post
end
def author?
post.user == user
end
def update?
author? || user.admin? || user.moderator?
end
def create?
author? || user.admin?
end
def destroy?
author? || user.admin?
end
# etc.
end
Now whenever you need to check user's ability to perform action, you can simply invoke:
# in controller
def update
#post = Post.find(params[:id])
authorize #post
# do whatever required
end
# in view
<% if policy(post).update? %>
<%= link_to 'Edit Post', post_edit_path(post) %>
<% end %>
As you can see Pundit is very easy to comprehend and it uses the same "convention over configuration" approach as Rails. At the same time it's very flexible and allows you to test virtually anything.
You will definitely need Pundit or any similar gem to manage permission in your ambitious app.
Right now in my rails 4 app after the user submits a post I want the app to redirect/render the show view, but right now it just goes to the create view. Here is my Posts controller:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id]) # show
end
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
private
def post_params
params.require(:post).permit(:Title, :Body) #whatsoever your post has
end
#redirect_to post_path(#post)
if #post.save
redirect_to #post.find(params[:id])
else
render :new
end
end
Here are my routes:
Rails.application.routes.draw do
root :to => "pages#index"
devise_for :users
resources :users
resources :pages
resources :posts
end
Thanks for your help.
Looks like there's a few bits of code in wrong places - end statements, and your final if statement at the bottom, which doesn't seem to be in any method.
Something like this should work:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id]) # show
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post.find(params[:id])
else
render :new
end
end
private
def post_params
params.require(:post).permit(:title, :body) #whatsoever your post has
end
end
First, the redirect is wrong. It should be simply:
redirect_to #post
After fixing that, it could be re-rendering because there was an error validating the #post. If #post.save fails the form will be re-rendered, but the URL will stay pointed at the create action.
First time poster, long time lurker here. I have a Users model and controller for a little video game application for Rails that I'm currently making. So I've read a couple of answers on here regarding this issue, but none of the answers really seem to have helped me. People have suggested adding a "user_id" column to my Users table, but my point of contention is, I thought the "user_id" was automatically made in Rails? Even if I use a user.inspect, I still see a user_id=7show up on the page. However, I still get the unknown attribute error when attempting to create a game and assign to the current user. Any help would be most appreciated in pinpointing the cause and solution to this. Thanks!
app/controllers/users_controller.rb:
class UsersController < ApplicationController
skip_before_filter :require_authentication, only: [:new, :create]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
#user = current_user
end
def create
#user = User.create!(user_params)
session[:user_id] = #user.id
redirect_to users_path, notice: "Hi #{#user.username}! Welcome to DuckGoose!"
end
def update
current_user.update_attributes!(user_params)
redirect_to users_path, notice: "Successfully updated profile."
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_url, notice: 'User was successfully destroyed.'
end
private
def user_params
params.require(:user).permit(:username, :firstname, :lastname, :email, :password, :password_confirmation)
end
end
app/config/routes.rb:
NkuProject::Application.routes.draw do
resources :users do
resources :games
end
resources :sessions
resources :games
get "sign_out", to: "sessions#destroy"
get "profile", to: "users#edit"
root to: "sessions#new"
end
app/controllers/games_controller.rb
class GamesController < ApplicationController
def new
#game = Game.new
end
def index
#games = Game.all
end
def destroy
#game = Game.find(params[:id])
#game.destroy
redirect_to games_url, notice: 'Game was successfully deleted.'
end
def create
#game = current_user.games.build(game_params)
if #game.save
redirect_to #game, notice: "Game successfully added"
else
render :new
end
end
def show
#game = Game.find(params[:id])
end
private
def game_params
params.require(:game).permit!
end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :require_authentication
def current_user
#current_user ||= User.find_by(id: session[:user_id]) if session[:user_id].present?
end
helper_method :current_user
def require_authentication
if current_user
true
else
redirect_to new_session_path
end
end
end
I'm sure I'm missing some code to put in for reference, but if I need anything else please let me know.
Looking at the way your controller actions are defined, I can safely say that User and Game have a 1-M relationship, i.e.,
class User < ActiveRecord::Base
has_many :games
end
class Game < ActiveRecord::Base
belongs_to :user
end
Now, based on that games table must have a field named user_id. Rails is not going to create it for you unless you specify it. You need to add field user_id in games table by creating a migration for the same. Right now, it doesn't seem like you have user_id foreign_key field in games table. Hence, the error while saving games record.
Building a forum in ruby for fun and to learn the language. To start this off, i understand basic constructs, but I am very new to server-side languages and am primarily a front-end developer. I am trying to extend my skills.
I don't necessarily want you to code for me (although code examples would be appreciated), but I would like you to explain to me why my code is terrible, which I'm sure it is and tell me how to fix it. Just need some help understand how to relate two models togethers and how to set up that relation in the controllers.
Thanks!
Here are my two models:
Post model:
class Post < ActiveRecord::Base
belongs_to :topic
end
Topic model:
class Topic < ActiveRecord::Base
belongs_to :user
has_many :posts
end
Now here come the controllers. These are where I am really lost. I got the topic creation working, and I tried to just copy what I did in the topic controller. I pretty much knew it wasn't going to work, but I am sorta lost. Here it is...
Topic Controller
class TopicsController < ApplicationController
def index
#topics = Topic.order("sticky desc")
end
def show
#topic = Topic.find(params[:id])
end
def new
#topic = Topic.new
end
def create
#topic = Topic.new(topic_params)
#topic.user = current_user
if #topic.save
redirect_to #topic, notice: "Created topic."
else
render :new
end
end
def edit
#topic = Topic.find(params[:id])
end
def update
#topic = Topic.find(params[:id])
if #topic.update_attributes(topic_params)
redirect_to topics_url, notice: "Updated topic."
else
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
#topic.destroy
redirect_to topics_url, notice: "Destroyed topic."
end
private
def topic_params
params.require(:topic).permit(:name, :post_content, :sticky)
end
end
Posts Controller
class PostsController < ApplicationController
def index
#posts = Post.order("sticky desc")
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
redirect_to topics_url, notice: "Post created."
else
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
if #post = Post.find(params[:id])
redirect_to topics_url, notice: "Updated post."
else
render :edit
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to topics_url, notics: "Post removed."
end
private
def post_params
params.require(:posts).permit(:content, :created_at, :updated_at)
end
end
I don't believe the views are an issue, and I will post a new question if there is once I get the controller logic figured out.
Again, any help would be appreciated. Please just no comments like, "you should really start back at the beginning", or "you aren't experienced enough, learn this first", because I know I am not experienced, hence why I am here asking you all.
You can show how you would code it, or just explain the logic that needs implemented to me, either is appreciated!
Thanks a ton everyone!
EDIT
I am getting a routing error actually. So obviously the routing is wrong, wasn't sure if it had something to do with the controller code tho: Here is the specific error. (this occurs when I try to click into a topic (I can edit and destroy topics, just not click into them)
Routing Error
No route matches {:action=>"new", :controller=>"posts"}
Try running rake routes for more information on available routes.
Here is my routes files so far:
Forum::Application.routes.draw do
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
resources :sessions
resources :topics do
resources :posts
end
resources :users
root to: 'topics#index'
end
Serve is a little Rack-based web server that makes it simple to serve ERB or HAML from any index. Serve is an optimal apparatus for building HTML models of Rails applications. Serve can likewise deal with SASS, Textile, and Markdown in the event that the suitable diamonds are introduced.
enter image description here