Photo Gallery Association of Models - ruby-on-rails-3

I'm trying to setup a photo gallery for each user. How would I set up the associations?
class User < ActiveRecord::Base
has_many :photos
has_many :galleries, through :photos
end
class Gallery < ActiveRecord::Base
has_many :photos
belongs_to :user
end
class Photo < ActiveRecord::Base
belongs_to :gallery
belongs_to :user
end
i have the gallery and photo model currently working. You are able to create a gallery and add photos to it. I'm confused is to how to add it to the current user?
class GalleriesController < ApplicationController
def index
#galleries = Gallery.all
end
def show
#gallery = Gallery.find(params[:id])
end
def new
#gallery = Gallery.new
end
def create
#gallery = Gallery.new(params[:gallery])
if #gallery.save
flash[:notice] = "Successfully created gallery."
redirect_to #gallery
else
render :action => 'new'
end
end
def edit
#gallery = Gallery.find(params[:id])
end
def update
#gallery = Gallery.find(params[:id])
if #gallery.update_attributes(params[:gallery])
flash[:notice] = "Successfully updated gallery."
redirect_to gallery_url
else
render :action => 'edit'
end
end
def destroy
#gallery = Gallery.find(params[:id])
#gallery.destroy
flash[:notice] = "Successfully destroyed gallery."
redirect_to galleries_url
end
end
PhotosController
class PhotosController < ApplicationController
def new
#photo = Photo.new(:gallery_id => params[:gallery_id])
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
flash[:notice] = "Successfully created Photo."
redirect_to #photo.gallery
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(params[:id])
end
def update
#photo = Photo.find(params[:id])
if #photo.update_attributes(params[:photo])
flash[:notice] = "Successfully updated Photo."
redirect_to #Photo.gallery
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully destroyed Photo."
redirect_to #photo.gallery
end
end

Once you grab the current user, just concatenate the gallery to the user's galleries.
def update
#gallery = Gallery.find(params[:id])
#user = current_user
if #gallery.update_attributes(params[:gallery])
#user.galleries << #gallery
flash[:notice] = "Successfully updated gallery."
redirect_to gallery_url
else
render :action => 'edit'
end
end

Related

Rails passing value from view to controller

I tried to generate some random no of string. But the number of generated string is decided by user.
User will enter the number of string in view page and it will be received by controller and Faraday will generate the number of paragraph user want, But i am not able to do this.
ApplicationController
class ApplicationController < ActionController::Base
private
def baconipsum
#baconipsum ||= Faraday.new("https://baconipsum.com/") do |f|
f.response :json
end
end
end
ArticlesController:
# frozen_string_literal: true
class ArticlesController < ApplicationController
http_basic_authenticate_with name: 'deba', password: '12345', except: %i[index show]
before_action :set_value
def index
#articles = Article.all
end
def show
#bacon = baconipsum.get("api/", type: 'all-meat',paras: #value).body
#article = Article.find(params[:id])
end
def showData
#value = params[:value] #tried to get value from user and using set_value function tried to make it global, so that show method will get the new value of value from showData method.
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def delete
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
def set_value
#value = 0
end
end
views from getting user input:
<%= form_for:article do %>
<label for="value">Value</label>
<%= text_field_tag :value %>
<%= submit_tag "Submit" %>
<% end %>
routes.rb
# frozen_string_literal: true
Rails.application.routes.draw do
root 'articles#index'
delete 'articles/:id', to: 'articles#delete'
resources :articles do
resources :comments
end
end

Allow non registered users to view content with pundit

I have having trouble allowing non-registered/non-logged in users to view the index and show pages for a blog section. I am using Pundit for authorization and realize that at the moment I have my policies set to not allow non-users to view any part of the blog section, but I have no idea how to work around that to have no policy for the index and show page.
My goal is to have the following:
Allow Admin and Editors to view, create, edit, and delete blogs
This portion works pefect
Allow registered users to view blogs
This portion works perfect
Allow non-registered/non-logged in users to view blogs
This part does not work
When I try to view the index page as a non-registered/non-logged in user, I will get an access denied flash message that comes out of my application controller, which is doing what it is supposed to be doing given the current policies.
So my question is: How do I modify my policies to allow non-registered/non-logged in users to view the index and show pages only?
Application Controller
class ApplicationController < ActionController::Base
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
private
def user_not_authorized(exception)
flash[:danger] = "Access denied. You are not authorized to view that page."
redirect_to (request.referrer || root_path)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) }
devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:username, :email, :password, :password_confirmation, :current_password)}
end
end
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user
#user = user
#record = record
end
def index?
true
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin?&.editor?&.user?
scope.all
else user != admin? || editor? || user?
scope
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
user.admin? || user.editor?
end
def create?
user.admin? || user.editor?
end
def update?
user.admin? || user.editor?
end
def destroy?
user.admin? || user.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized, only: [:destroy]
def index
#meta_title = "Blog"
#meta_description = "page description here"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(permitted_attributes(#post))
authorize #post
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end
I've seen a similar question asked Pundit policy_scoper error, but the solution suggested there does not seem to work in my case.
After much frustration, I was finally able to solve the issue. Big thanks go out to #Scott for helping get the controller and testing set up as they should be, and nearly getting the policies working.
Turns out that the raise Pundit::NotAuthorizedError, "must be logged in" unless user in the initializer section of the Application Policy was not allowing non-logged-in users from accessing the index page (just like it's supposed to when you want a closed system...). Since my application is open for anyone to view in the index and show pages of the blog, I needed to remove that line.
Once removed the application would then throw a undefined method admin?' for nil:NilClass for non-logged-in users trying to access the blog index page. This was solved by using the correct conventions of identifying users in Post Policy. For each def in the policy I had user.admin? || user.editor?. That needed to be changed to user&.admin? || user&.editor?.
The code ended up as follows:
Application Policy
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope
end
end
end
Post Policy
class PostPolicy < ApplicationPolicy
attr_reader :post
class Scope < Scope
def resolve
if user&.admin? || user&.editor?
scope.all
else
end
end
end
def permitted_attributes
if user.admin? || user.editor?
[:title, :body, :image, :permalink, :description, :tag_list, :username]
else
[:title, :body, :image, :username]
end
end
def index?
true
end
def show?
true
end
def new?
admin_or_editor
end
def create?
admin_or_editor
end
def update?
admin_or_editor
end
def destroy?
admin_or_editor
end
private
def admin_or_editor
user&.admin? || user&.editor?
end
end
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
after_action :verify_authorized, except: [:index, :show]
def index
#meta_title = "Blog"
#meta_description = "blog description"
#posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4)
end
def show
#meta_title = #post.title
#meta_description = #post.description
end
def new
#meta_title = "Add New Blog"
#meta_description ="Add a new blog."
#post = Post.new
authorize #post
end
def edit
#meta_title = "Edit Blog"
#meta_description ="Edit an existing blog."
authorize #post
end
def create
#post = Post.new
#post.update_attributes(permitted_attributes(#post))
#post.user = current_user if user_signed_in?
authorize #post
if #post.save
redirect_to #post, notice: 'Post was successfully created.'
else
render :new
end
end
def update
#post = Post.find(params[:id])
authorize #post
if #post.update_attributes(permitted_attributes(#post))
redirect_to #post, notice: 'Post was successfully updated.'
else
render :edit
end
end
def destroy
if #post.present?
#post.destroy
authorize #post
else
skip_authorization
end
redirect_to posts_url, notice: 'Post was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Only allow the white list through.
def post_params
params.require(:post).permit(policy(#post).permitted_attributes)
end
end

Polymorphic Comments with Ancestry Problems

I am trying to roll together two Railscasts: http://railscasts.com/episodes/262-trees-with-ancestry and http://railscasts.com/episodes/154-polymorphic-association on my app.
My Models:
class Location < ActiveRecord::Base
has_many :comments, :as => :commentable, :dependent => :destroy
end
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
My Controllers:
class LocationsController < ApplicationController
def show
#location = Location.find(params[:id])
#comments = #location.comments.arrange(:order => :created_at)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #location }
end
end
end
class CommentsController < InheritedResources::Base
def index
#commentable = find_commentable
#comments = #commentable.comments.where(:company_id => session[:company_id])
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
#comment.user_id = session[:user_id]
#comment.company_id = session[:company_id]
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
In my locations show view I have this code:
<%= render #comments %>
<%= render "comments/form" %>
Which outputs properly. I have a _comment.html.erb file that renders each comment etc. and a _form.html.erb file that creates the form for a new comment.
The problem I have is that when I try <%= nested_comments #comments %> I get undefined method 'arrange'.
I did some Googling and the common solution to this was to add subtree before the arrange but that throws and undefined error also. I am guessing the polymorphic association is the problem here but I am at a loss as to how to fix it.
Dumb mistake... forgot to add the ancestry gem and required migration which I thought I had already done. The last place I checked was my model where I eventually discovered my error.

Rails 3 NoMethod Error - undefined method for profile in Profiles#edit with CanCan

In my Rails 3 app, I'm getting redirected to login during my signup process. The steps to signup are supposed to be:
User creates User and Profile
Upon saving user, user is logged into the app and redirected to Profiles#edit (/signup/join)
Upon saving profile, user is redirect to Profiles#show (/profiles/:id)
I'm getting redirected to /login after step 1, and I'm seeing a 302 error after the redirect. If I comment out my before_filter :authenticate in profiles_controller.rb and redo the steps above I don't get redirected out of /signup/join but I get the following error:
NoMethodError in ProfilesController#edit
undefined method `profile' for nil:NilClass
I'm pointed to the first line of my Profiles#edit action:
def edit
#profile = user.profile
if #profile.higher_ed?
higher_ed = HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
employer = Employer.find_or_create_by_name(:name => #profile.employer)
end
render :layout => "join_form"
end
I've been making an attempt to implement CanCan in my app, so I thought that was the cause. However I commented out my entire ability.rb file and the problem persists. I'd obviously like to figure out how to fix this without commenting out the before_filter. So if anyone has an idea I'd greatly appreciate it. Since I'm dealing with CanCan which depends on a current_user, I'll start with the definition of current_user in my application_controller.rb:
protected
# Returns the currently logged in user or nil if there isn't one
def current_user
return unless session[:user_id]
#current_user ||= User.find_by_id(session[:user_id])
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
# Make current_user available in templates as a helper
helper_method :current_user
Here's my users_controller.rb:
class UsersController < ApplicationController
before_filter :authenticate, :only => [:edit, :update, :index]
layout "application"
def new
#user = User.new
#user.profile = Profile.new
if logged_in?
redirect_to current_user.profile
end
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to join_path, :notice => 'User successfully added.'
UserMailer.registration_confirmation(#user).deliver
else
render :action => 'new'
end
end
My profiles_controller.rb:
class ProfilesController < ApplicationController
#before_filter :authenticate, :only => [:edit, :update]
helper_method :find_or_create_group
layout "application", :except => [:edit, :show]
def new
#profile = Profile.new(params[:profile])
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to #user.profile, :notice => 'User successfully added.'
else
render :new
end
if #profile.higher_ed?
HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
Employer.find_or_create_by_name(:name => #profile.employer)
end
if #profile.job_title?
JobTitle.find_or_create_by_name(:name => #profile.job_title)
end
if #profile.high_school?
HighSchool.find_or_create_by_name(:name => #profile.high_school)
end
end
def user
#user = current_user
end
def edit
#profile = user.profile
if #profile.higher_ed?
higher_ed = HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
employer = Employer.find_or_create_by_name(:name => #profile.employer)
end
render :layout => "join_form"
end
My sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
if user = User.authenticate(params[:email].downcase, params[:password])
session[:user_id] = user.id
cookies.permanent[:auth_token] = user.auth_token
if user.profile.higher_ed?
redirect_to user.profile, :notice => "Logged in successfully"
else
redirect_to join_path, :notice => "Logged in successfully"
end
else
flash.now[:alert] = "Invalid login/password. Try again!"
render :action => 'new'
end
end
def destroy
reset_session
cookies.delete(:auth_token)
redirect_to root_path, :notice => "You successfully logged out"
end
end
My ability.rb for CanCan:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new guest user
if user.role? :admin
can :manage, :all
else
can :manage, :all
end
end
end
My routes.rb:
match "/signup/join" => "profiles#edit", :as => 'join'
#profile = user.profile
Try changing the above line to
#profile = #current_user.profile
or
#profile = current_user.profile
The issue has nothing to do with cancan, rather it has to do with "user" being nil in your controller.
I got it working by reworking my current_user logic. It's now:
def current_user
#current_user ||= lookup_user
end
def lookup_user
if cookies[:auth_token]
User.find_by_auth_token!(cookies[:auth_token])
elsif session[:user_id]
User.find_by_id(session[:user_id])
end
end
That seems to have done the trick.

Render alternate view in ruby on rails

I have the following code in my controller
def create
#severity = Severity.new(params[:severity])
if #severity.save
flash[:notice] = "Successfully created severity"
render 'save'
end
end
I am trying to get the method to render another view file other than create.js.erb however the controller always renders the default rather than the save.js.erb.
Any ideas on what could be wrong?
def create
#severity = Severity.new(params[:severity])
if #severity.save
flash[:notice] = "Successfully created severity"
respond_to do |format|
format.js { render :template => "/path/to/save" }
end
end
end
or
def create
#severity = Severity.new(params[:severity])
if #severity.save
flash[:notice] = "Successfully created severity"
respond_to do |format|
format.js { render :file => "/path/to/save.js.erb" }
end
end
end
try this
def create
#severity = Severity.new(params[:severity])
if #severity.save
flash[:notice] = "Successfully created severity"
end
render :file => "/path/to/save.js.erb"
end