Rails 4 Paperclip with Devise, file saving error - ruby-on-rails-4

I'm using devise gem with paperclip to handle authentication and upload pictures. Problem is that I have used paperclip on the same model twice for storing two pictures (let's call those paperclip columns :avatar , :superbadge), my model name is User.
Now, when I choose to upload two pictures, my rails application ignores the first file that I have chosen, instead It uses second chosen file and saves it in the first paperclip column, leaving second paperclip column blank. How do I fix it?
My application controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_devise_permitted_parameters, if: :devise_controller?
protected
def configure_devise_permitted_parameters
registration_params = [:name, :email, :password, :password_confirmation,:avatar,:superstarbadge]
if params[:action] == "update"
devise_parameter_sanitizer.for(:account_update) {
|u| u.permit(registration_params << :current_password)
}
elsif params[:action] == "create"
devise_parameter_sanitizer.for(:sign_up) {
|u| u.permit(registration_params)
}
end
end
end
My User.rb model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :validatable
has_attached_file :avatar, :styles => { :small => "100x100>" }
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
has_attached_file :superstarbadge, :styles => { :tiny => "100x100>" }, :default => "superbadge.jpg"
validates_attachment_content_type :superstarbadge, :content_type => /\Aimage\/.*\Z/
has_many :questions
has_many :answers
def to_s
email
end
end
My form_for for creating new user with devise gem (I'm using slim template language not erb):
h1 Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => { :multipart => true }) do |f|
= devise_error_messages!
.field
label= f.label :name
= f.text_field :name, autofocus: true
.field
label= f.label :email
= f.email_field :email, autofocus: true
.field
label= f.label :password
= f.password_field :password, autocomplete: 'off'
.field
label= f.label :password_confirmation
= f.password_field :password_confirmation, autocomplete: 'off'
.field
= f.label :avatar
= f.file_field :avatar
.field
= f.file_field :avatar
div
= f.submit "Sign up"

Both the file_field's in your form are referring to avatar field so when you submit the form the second chosen file (i.e., latest) gets saved as avatar. There is no file_field for superstarbadge so it never gets saved.
You need one file_field for avatar and other one for superstarbadge. So, your code should look like:
.field
= f.label :avatar
= f.file_field :avatar
.field
= f.file_field :superstarbadge ## This one should be superstarbadge and NOT avatar

Related

Getting "Unpermitted parameters" error for deivse

Hi am working on sample app where I am using devise for authentication.
I am adding following extra parameters while registration.
:first_name, :last_name, :mobile, :gender, :address
But I am getting following Unpermitted parameters: first_name, last_name, password_confirmation error while registering new user.
I refereed following links
Add Custom Field/Column to Devise with Rails 4
http://www.jacopretorius.net/2014/03/adding-custom-fields-to-your-devise-user-model-in-rails-4.html
But it didn't worked. Here is not code set
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_confirmation_of :password, :only => :create
end
I also implemented same in application controller but it didn't worked so I created separate
registration controller.
registration_controller.rb
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name, :mobile, :gender, :address, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:name,
:email, :password, :password_confirmation, :current_password)
end
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
private
def after_sign_in_path_for(resource)
user_landing_page
end
def user_landing_page
contact_us_path
end
end
devise/registration/new.html.haml
.container
.row
.col-sm-6.col-md-4.col-md-offset-4
%h1.text-center.login-title Create New Account
.account-wall
%img.profile-img{:alt => "", :src => "https://lh5.googleusercontent.com/-b0-k99FZlyE/AAAAAAAAAAI/AAAAAAAAAAA/eu7opA4byxI/photo.jpg?sz=120"}
= form_for(resource, as: resource_name, class: "form-signin input-medium", url: session_path(resource_name)) do |f|
= f.text_field :first_name, class: "form-control", placeholder: "First Name", autofocus: true
= f.text_field :last_name, class: "form-control", placeholder: "Last Name", autofocus: true
= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true
= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off"
= f.password_field :password_confirmation, class: "form-control", placeholder: "Confirm Password", autocomplete: "off"
= f.submit "Log in", class: "btn btn-lg btn-primary btn-block login-button"
development.log
Parameters: {"utf8"=>"✓", "authenticity_token"=>"pe7wBW3iWnn39p3nJAi8utbuECj+x8zX/pIxr/6sKbo=", "user"=>{"first_name"=>"first_name", "last_name"=>"last_name", "email"=>"admin#my.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Log in"}
Unpermitted parameters: first_name, last_name, password_confirmation
Rendered devise/sessions/new.html.haml within layouts/application (6.6ms)
Rendered layouts/_home_header.html.haml (1.2ms)
Completed 200 OK in 426ms (Views: 316.8ms | ActiveRecord: 0.0ms)
routes.rb
Rails.application.routes.draw do
root :to => 'landing#index'
devise_for :users, :controllers => {:registrations => "registrations"}
get '/about_us' => 'statics#about_us', as: :about_us
get '/contact_us' => 'statics#contact_us', as: :contact_us
end
can any one suggest what I am missing.
I am using Rails 4.1.4, ruby 2.1.2 and devise 3.4.1.
As per my understanding, you are registering new user. Here is your mistake
= form_for(resource, as: resource_name, class: "form-signin input-medium", url: session_path(resource_name)) do |f|
you are using session_path that means you are going to "Log In" not for "Sign Up". So change it
= form_for(resource, as: resource_name, class: "form-signin input-medium", url: registration_path(resource_name)) do |f|

Unexpected NoMethodError after migration to add new column

I have a player model inheriting from a user model to share authentication logic (devise) with a 3rd model (coach that also inherits from user).
class User < ActiveRecord::Base
end
class Player < User
end
class Coach < User
end
I'm trying to add a field to the player table when players register so I created a migration
rails g migration AddClubCoachEmailToPlayer club_coach_email:string
then ran the migration
rake db:migrate
for the file
class AddClubCoachEmailToPlayer < ActiveRecord::Migration
def change
add_column :players, :club_coach_email, :string
end
end
Schema as expected
create_table "players", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "club_coach_email"
end
Now, I need to add the field to /views/players/registrations/new
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
#...
<div><%= f.label :position %><br />
<%= f.radio_button(:position, "Striker") %> Striker
<%= f.radio_button(:position, "Midfielder") %> Midefielder
<%= f.radio_button(:position, "Defender") %> Defender
</div>
<div><%= f.label :club_coach_email %><br />
<%= f.email_field :club_coach_email %></div>
<div><%= f.label :profile_name %><br />
<%= f.text_field :profile_name %></div>
#...
and I sanitize params through this technique from devise wiki; in lib/player_sanitizer.rb I add the new field.
class PlayerParameterSanitizer < Devise::ParameterSanitizer
private
def sign_up
default_params.permit(:first_name, :last_name, :profile_name, :password, :password_confirmation, :email, :grad_year, :position, :club_team, :formation, :club_coach_email)
end
def account_update
default_params.permit(:first_name, :last_name, :profile_name, :password, :password_confirmation, :email, :grad_year, :position, :club_team, :formation)
end
end
This is what my application controller looks like
class ApplicationController < ActionController::Base
def after_sign_in_path_for(user)
dashboard_path
end
protected
def devise_parameter_sanitizer
if resource_class == Player
PlayerParameterSanitizer.new(Player, :player, params)
elsif resource_class == Coach
CoachParameterSanitizer.new(Coach, :coach, params)
else
super
end
end
end
However, I must be missing some step because when I navigate to /players/sign_up I'm getting a NoMethodError in Players::Registrations#new
undefined method `club_coach_email' for #<Player:0x00000109296be8>
Obvioulsy, here is where the trace is pointing
<%= f.radio_button(:position, "Defender") %> Defender
</div>
<div><%= f.label :club_coach_email %><br />
<%= f.email_field :club_coach_email %></div>
<div><%= f.label :profile_name %><br />
<%= f.text_field :profile_name %></div>
What do I seem to not understand here?
As for me you're doing it too complex. From the information you gave there is no different functionality between this three different users types, therefore it will be easier to make all of them not through inheritance but with the devise roles.
In this way you'll have One user model with three different roles (User, Player, Coach).
Or there is other way - using different models in "devise way":
rails g devise User + rails g devise Player + rails g devise Coach
After this you'll get three almost separate models each with all devise functionality and methods (for example: player_signed_in?, current_coach, authenticate_player! etc.).

Rails nested_form Invalid association. Make sure that accepts_nested_attributes_for is used for assoctiation

I am using rails 4.0.4 with nested_form 0.3.2 to build an app that allows users to organize movies in lists.
I have these main models, a List model (I've excluded things such as validations):
class List < ActiveRecord::Base
belongs_to :user
has_many :list_movie_pairs
has_many :movies, :through => :list_movie_pairs
accepts_nested_attributes_for :list_movie_pairs, :allow_destroy => true
accepts_nested_attributes_for :movies, :allow_destroy => true
end
A Movie model:
class Movie < ActiveRecord::Base
has_many :list_movie_pairs
has_many :lists, :through => :list_movie_pairs
has_many :reviews
end
A ListMoviePair model for the many-to-many relationship:
class ListMoviePair < ActiveRecord::Base
belongs_to :list
belongs_to :movie
validates_presence_of :list_id, :movie_id
validates_uniqueness_of :movie_id, scope: :list_id
end
I am trying to build an interface for the user to add movies to a created list. These routes serve my purpose:
get "/users/:username/lists/:id/add" => "lists#add_movies", :as => :user_list_list_movie_pairs
post "/users/:username/lists/:id/add" => "lists#submit_movies"
These are the classes in my ListsController that should make this possible:
def add_movies
#pair = list.list_movie_pairs.new # "list" is a helper that returns the current list
end
def submit_movies
#list = current_user.lists.find(params[:id])
#pair = #list.list_movie_pairs.new(pair_params)
if #pair.save
redirect_to user_list_path(current_user.username, #list)
else
render :add_movies
end
end
def list_params
params.require(:list).permit(:name, :description, :private, \
list_movie_pairs_attributes: [:id, :list_id, :movie_id, :_destroy], \
movies_attributes: [:id, :title, :_destroy])
end
And this is the form in my view
<%= nested_form_for [current_user, list, #pair] do |f| %>
<%= f.fields_for :movies do |movie_form| %>
<%= movie_form.text_field :title %>
<%= movie_form.link_to_remove "Remove movie" %>
<% end %>
<%= f.link_to_add "Add movie", :movies %>
<% end %>
I get this error when trying to access the view:
Invalid association. Make sure that accepts_nested_attributes_for is used for :movies association.
Which pops at this line:
<%= f.link_to_add "Add movie", :movies %>
Note 1: I am using the Devise gem for users, hence the "current_user" helper;
Note 2: I have tried using both "movies" and "list_movie_pairs", i.e.:
f.fields for :list_movie_pairs
and
f.link_to_add "Add movie", :list_movie_pairs
in my view, neither association seems to work
Your code in the view should be like this
<%= nested_form_for [current_user, list, #pair] do |f| %>
<%= f.fields_for :movies do |movie_form| %>
<%= movie_form.text_field :title %>
<%= movie_form.link_to_remove "Remove movie" %>
<%= movie_form.link_to_add "Add movie", :movies %> #note the change here
<% end %>
<% end %>
Update
There are several issues in your code
1.In your List model,this line is not required
accepts_nested_attributes_for :movies, :allow_destroy => true #not requied
2.In your ListsController,you have this line
#pair = #list.list_movie_pairs.new(pair_params)
It should be
#pair = #list.list_movie_pairs.new(list_params) because you have list_params method not pair_params

activeadmin carrierwave image hint not displayed

HI I am using active admin with carrier gem. I am unable to view preview on image upload in hint
my image src is always empty i.e f.template.image_tag(f.object.image.url) is empty
I can see image relative url after clicking upload button.
my form looks like this
ActiveAdmin.register Product do
permit_params :name, :description , :category_id , :image
form(:html => { :multipart => true }) do |f|
f.inputs "Product" do
f.input :category_id , :as => :select , :collection => Category.all
f.input :name
f.input :description
f.input :image, :as => :file, :hint => f.template.image_tag(f.object.image.url)
end
f.actions
end
end
model
class Product < ActiveRecord::Base
belongs_to :category
mount_uploader :image, ImageUploader
end
serializer
class ProductSerializer < ActiveModel::Serializer
attributes :id, :name, :description , :image
end
my uploader looks like this
class ImageUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
GENERATE HTML
<label class="label" for="product_image">Image</label>
<input id="product_image" name="product[image]" type="file">
<p class="inline-hints"><img src=""></p>
After a few modifications, for me works fine:
ActiveAdmin.register Team do
permit_params :name, :country :image
index do
selectable_column
column :nome
column :country
actions
end
form do |f|
f.inputs "Team" do
f.input :nome
f.input :country
f.input :image, :image_preview => true
end
f.actions
end
show do
attributes_table do
row :nome
row :country
row :image do
image_tag(equipe.image.url)
end
end
end
end
You can see that I use three options:
- Index: to show the list of items
- Form: for the form
- Show: to show the item details
This way you can customize all pages.

Rails 4.0 with Devise 3.0

I've been looking at my code for some time now and can't work out where the errors are with Devise. I've added a few additional lines to the Sign Up view and changed everything as described in the Devise Readme, but the additional fields are not showing up, only the usual Email, Password and Confirm Password fields are. My users are called Knockers, in case anyone was wondering!
Here is my views page (registrations\new.html.erb):
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.text_field :first_name %></div>
<div><%= f.text_field :last_name %></div>
<div><%= f.text_field :username %></div>
<div><%= f.text_field :gender %></div>
<div><%= f.date_field :dob %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Facebook", knocker_omniauth_authorize_path(:facebook) %>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Twitter", knocker_omniauth_authorize_path(:twitter) %>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Google", knocker_omniauth_authorize_path(:google_oauth2) %>
<% end %>
<%= render "knockers/shared/links" %>
My model page (\knocker.rb)
Class Knocker < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook, :twitter, :google_oauth2]
before_save { self.username = username.downcase }
validates :first_name, presence: true,
length: { maximum: 25 }
validates :last_name, presence: true,
length: { maximum: 25 }
VALID_USERNAME_REGEX = /\A[\w+\-._]+\z/i
validates :username, presence: true,
length: { maximum: 20 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
validates :email, presence: true
validates :password, presence: true
validates :dob, presence: true
validates :gender, presence: true
validates :postcode, presence: true
def self.find_for_facebook_oauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |knocker|
knocker.provider = auth.provider
knocker.uid = auth.uid
knocker.email = auth.info.email
knocker.password = Devise.friendly_token[0,20]
#knocker.first_name = auth.info.name # assuming the user model has a name
#knocker.image = auth.info.image # assuming the user model has an image
end
end
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
knocker = Knocker.where(:provider => auth.provider, :uid => auth.uid).first
if knocker
return knocker
else
registered_knocker = Knocker.where(:email => auth.uid + "#twitter.com").first
if registered_knocker
return registered_knocker
else
knocker = Knocker.create(full_name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.uid+"#twitter.com",
password:Devise.friendly_token[0,20],
username:auth.info.nickname,
about:auth.info.description )
end
end
end
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
data = access_token.info
knocker = Knocker.where(:provider => access_token.provider, :uid => access_token.uid ).first
if knocker
return knocker
else
registered_knocker = Knocker.where(:email => access_token.info.email).first
if registered_knocker
return registered_knocker
else
knocker = Knocker.create(first_name: data["first_name"],
last_name: data["last_name"],
provider:access_token.provider,
email: data["email"],
uid: access_token.uid ,
password: Devise.friendly_token[0,20],
gender: data["gender"],
dob: data["birthday"]
)
end
end
end
def self.new_with_session(params, session)
super.tap do |knocker|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
knocker.email = data["email"] if knocker.email.blank?
end
end
end
def name
first_name + " " + last_name
end
end
My database migration:
class DeviseCreateKnockers < ActiveRecord::Migration
def change
create_table(:knockers) do |t|
t.string :first_name, :null => false
t.string :last_name, :null => false
t.string :username, :null => false
t.string :town
t.string :postcode
t.float :latitude
t.float :longitude
t.date :dob, :null => false
t.text :about
t.string :gender, :null => false
t.string :nationality
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Omniauth data
t.string :provider
t.string :uid
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :knockers, :email, :unique => true
add_index :knockers, :reset_password_token, :unique => true
add_index :knockers, :username, :unique => true
add_index :knockers, :latitude
add_index :knockers, :longitude
add_index :knockers, :dob
# add_index :knockers, :confirmation_token, :unique => true
# add_index :knockers, :unlock_token, :unique => true
end
end
and finally my Application Controller:
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 :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :first_name, :last_name, :gender, :dob, :email, :password, :password_confirmation) }
end
end
Any help would be greatly appreciated. I've looked on here through a few problems, but most of them just seem to be in getting the wrong field type... can't see what the problem is here unless it's something to do with a badly implemented OAuth problem.
Rename the knockers folder under application_name/app/views directory to devise.
While generating the views you by mistake generated them as rails generate devise:views knockers instead of rails generate devise:views.
You use rails generate devise:views knockers to generate views if you have multiple devise models and you need different views(customizations) for them.