Strong params rails 4 permitting params - ruby-on-rails-4

Here is what my params look like,
{
:project_id => "1",
:ticket => {:name => "Ticket1"}
}
How do I add the project_id to the permitted params?
Controller
params.require(:ticket).permit(:name)

Here is what I did
I added another function for project params
def ticket_group_params
params.require(:ticket_group).permit(:name)
end
def project_params
params.permit(:project_id)
end
Then I just merge the results only for the create action eg.
# POST /ticket_group
# POST /ticket_group.json
def create
#ticket_group = TicketGroup.new(ticket_group_params.merge(project_params))
respond_to do |format|

def ticket_params
name_params = params.require(:ticket).permit(:name)
name_params.merge(params.permit(:project_id))
end
# => {name: 'val', project_id: 'val'}
or
def ticket_params
params.require(:ticket).permit(:name).tap do |_params|
_params[:project_id] = params.permit(:project_id)
end
end
# => {name: 'val', project_id: 'val'}
or, it may be
def ticket_params
params.permit(:project_id, ticket: [:name])
end
# => {project_id: 'val', ticket: {name: 'val'}}

You likely need to add this as a hidden attribute on your form, like so:
<input type="hidden" name="ticket[project_id]" value="<%= #ticket.project_id %>" />
Then in the controller you can do this:
params.require(:ticket).permit(:name,:project_id)
Here is a helpful link:
https://github.com/rails/strong_parameters

Related

Strong parameters with Rails 4.0 and Devise

I am using Rails 4.2 and devise.Request type will always be JSON.My registrations controller looks like this
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_sign_up_params, only: [:create]
def create
if request.format(request) == "application/json"
build_resource(sign_up_params)
if resource.save
render :json => {:success => "true", :message => "Thank You For Registering."}
else
render :json => {:success => "false", :message => resource.errors.full_messages}
end
else
super
end
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :password, :password_confirmation)
end
end
end
The parameters that show-up in the console is like :
Parameters: {"email"=>"test123#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "registration"=>{"email"=>"test123#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}}
The error it produces is that the controller doesn't recognize the email and password fields and always returns error like :
["Email can't be blank","Password can't be blank"]
Does this happen because of any foolishness that I have written in the code?Please help
Your configure_sign_up_params method has to be something like this to work.
def configure_sign_up_params
devise_parameter_sanitizer.for(:registration) do |u|
u.permit(:email, :password, :password_confirmation)
end
end
If you can see the console content what you have posted, it contains a hash with registration as a key:
"registration"=>{"email"=>"test123#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}

Rails 4 paperclip Background job

CURRENT LOGIC
First, I think I have read all the articles on paperclip and I'm still stucked despite all the infos learned... So I can say taht your help is really really precious.
Secondly, I do not use delayed_paperclip, nor s3_direct_upload (but jquery directUpload).
I have users profile with 4 differents pictures : logo, avatar, worka, workb
Each format (logo, avatar, worka, workb) has 3 styles (:small, :thumb, :medium)
User can update its pictures => so update action is concerned
The 4 files fields are in a form with other classic fields (name, email, ...)
Upload is managed by jQuery DirectUpload + Paperclip
When user click the file field to add an image:
jQuery DirectUpload uploads the file into a temp directory on s3
jQuery callbacks with the url(key)
The url is assigned as :temp to an hidden field generated in javascript
When form submit button is pressed:
I assign to paperclip the url of the file uploaded with direct upload, with the help of #user.logo.temp which contains the url(key)
Paperclip generates all styles
<input type="hidden" name="user[logo_attributes][temp]" value="https://bucketname.s3.amazonaws.com/temp/e4b46d01-5d69-483b.jpg">
MY PROBLEM: STYLES GENERATION BRINGS ME TO HEROKU IDLE and TIMEOUT #15 #12
.
ATTEMPTS: I tried to isolate the upload process to put it in a background job
.
I can't figure out how to block paperclip styles generation at the first upload and generate them after in a background job
before_post_process block all post process, even in background job
I didn't use .reprocess! Since paperclip 4, update is triggered and... infinite loop..., so I use .assign and .save instead
The file is correctly assigned from S3 hosted file, then processed by paperclip
I'm not sure about the file from file field, if it is uploaded or not (no trace of that in the console, but since the form is submited, the file too, even if unused.
.
NEED: STYLES BLOCKED THEN PROCESSING IN A BACKGROUND JOB
My Logo Model
class Logo < Document
S3_TEMP_URL_FORMAT = %r{\/\/bucketname\.s3\.amazonaws\.com\/(?<path>temp\/.+\/(?<filename>.+))\z}.freeze
has_attached_file :attachment,
styles: { medium: "300x300#" },
convert_options: { medium: "-quality 75 -strip" },
default_url: ":parent_type/:class/:style/missing.png",
path: "/documents/:parent_type/:id_partition/:class/:style/:basename.:extension"
validates_attachment :attachment,
content_type: { content_type: ["image/gif", "image/png", "image/jpg", "image/jpeg"] },
size: { less_than: 1.megabyte }
validates :temp,
# presence: true,
format: { with: S3_TEMP_URL_FORMAT }
before_save :set_attachment
after_save :set_remote_url
before_post_process :stop_process
def stop_process
false
end
def styles_process
self.attachment.assign(attachment)
self.save
end
def set_attachment
# puts "BEGIN -- SET ATTACHMENT"
tries ||= 5
s3_temp_url_data = S3_TEMP_URL_FORMAT.match(self.temp)
s3 = AWS::S3.new
s3_temp_head = s3.buckets[ENV['S3_BUCKET']].objects[s3_temp_url_data[:path]].head
self.attachment_file_name = s3_temp_url_data[:filename]
self.attachment_file_size = s3_temp_head.content_length
self.attachment_content_type = s3_temp_head.content_type
self.attachment_updated_at = s3_temp_head.last_modified
rescue AWS::S3::Errors::NoSuchKey => e
tries -= 1
if tries > 0
sleep(3)
retry
else
false
end
end
def set_remote_url
s3_temp_url_data = S3_TEMP_URL_FORMAT.match(self.temp)
s3 = AWS::S3.new
self.attachment = URI.parse(self.temp)
self.save
s3.buckets[ENV['S3_BUCKET']].objects.with_prefix(s3_temp_url_data[:path]).delete_all
end
end
My Controller
def update
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
#user = User.find(current_user.id)
if #user.update_attributes(account_update_params)
# Here is the styles processing
# This is where the Resque background job would go
#user.logo.styles_process
set_flash_message :notice, :updated
redirect_to after_update_path_for(#user)
else
render :edit
end
end
My Form
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), method: :put, html: { class: "form-horizontal directUpload", role: "form" }) do |f| %>
<%= f.fields_for :logo do |l| %>
<%= l.file_field(:attachment, accept: 'image/gif,image/png,image/jpg,image/jpeg') %>
<% end %>
<input type="hidden" name="user[logo_attributes][temp]" value="https://bucketname.s3.amazonaws.com/temp/e4b46d01-5d69-483b.jpg">
<% end %>

passing an id in Rails 4

If i start this question by showing you my routes: -
c:\Sites\work\easygifts>rake routes
Prefix Verb URI Pattern Controller#Action
writing_stores GET /stores/writing(.:format) stores#writing
office_stores GET /stores/office(.:format) stores#office
time_stores GET /stores/time(.:format) stores#time
home_stores GET /stores/home(.:format) stores#home
wellness_stores GET /stores/wellness(.:format) stores#wellness
travel_stores GET /stores/travel(.:format) stores#travel
bags_stores GET /stores/bags(.:format) stores#bags
leisure_stores GET /stores/leisure(.:format) stores#leisure
quote_stores GET /stores/quote(.:format) stores#quote
stores GET /stores(.:format) stores#index
POST /stores(.:format) stores#create
new_store GET /stores/new(.:format) stores#new
edit_store GET /stores/:id/edit(.:format) stores#edit
store GET /stores/:id(.:format) stores#show
PATCH /stores/:id(.:format) stores#update
PUT /stores/:id(.:format) stores#update
DELETE /stores/:id(.:format) stores#destroy
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:id/edit(.:format) products#edit
product GET /products/:id(.:format) products#show
PATCH /products/:id(.:format) products#update
PUT /products/:id(.:format) products#update
DELETE /products/:id(.:format) products#destroy
root GET / stores#index
The issue i am having is getting the :id into the 'quote' view.
I am wanting to see in my routes; quote_stores GET /stores/quote/:id(.:format) stores#quote Or something like it.
Can :id only be passed through CRUD?? I thought i could pass instance variables through pretty much anywhere so I wrote this in my view as the link to the view with the :id info passed into it.
<% #products.each do |office| %>
<div class="item">
<%= link_to image_tag(office.image_url), image_path(office.image_url), class: 'fancybox' %>
<p><strong><%= office.item_code%></strong>
</br><em><%= truncate(office.title, length: 18) %></em></p>
<p class="showArticle"><%= link_to 'Show Article', store_path(office) %></p>
<p class="addTo"><%= link_to 'Price Info', quote_stores_path(office) %></p>
</div>
<% end %>
I am referring to the <%= link_to 'Price Info', quote_stores_path(office) %> which upon click takes you to the correct view and in the URI path it even lists the correct :id however it does not pass into the view that :id's information.
My controller code is as follows: -
class StoresController < ApplicationController
add_breadcrumb 'home', :stores_path
def index
#products = Product.all
end
def show
#products = Product.find(params[:id])
if #products.nil?
redirect_to action: :index
end
add_breadcrumb 'Back', #products.section
end
def writing
#products = Product.where(:section => 'writing').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'writing', writing_stores_path
end
def office
#products = Product.where(:section => 'office').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'office', office_stores_path
end
def time
#products = Product.where(:section => 'time').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'time', time_stores_path
end
def home
#products = Product.where(:section => 'home').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'home', home_stores_path
end
def wellness
#products = Product.where(:section => 'wellness').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'wellness', wellness_stores_path
end
def travel
#products = Product.where(:section => 'travel').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'travel', travel_stores_path
end
def bags
#products = Product.where(:section => 'bags').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'bags', bags_stores_path
end
def leisure
#products = Product.where(:section => 'leisure').paginate(:per_page => 5, :page => params[:page])
add_breadcrumb 'leisure', leisure_stores_path
end
def quote
#products = Product.find_by(params[:id])
if #products.nil?
redirect_to action: :index
end
end
end
So apart from my code not being DRY, what am i missing here please? What am i not understanding about :id's?
In your config/routes.rb, you probably have this line:
resources :stores
Which creates routes for the standard CRUD actions of the stores resource. You can define additional actions for this resource which either apply to the collection (multiple products) or the members individually (a single product).
Please note that it would probably more logical to name the resource products rather than stores, since it seems to be handling Products.
In your case, you'd want to define an additional member action. Since it applies to a single product, Rails will define a route which takes an id parameter:
resources :stores do
member do
get 'quote'
end
end
This will generate the following route (rake routes):
quote_store GET /stores/:id/quote(.:format) stores#quote
Note that the route is called quote_store, the singular form rather than the plural.
Also see the Rails guides for more information about collection and member routes.

How to send multiple files using dropzone.js with Rails?

Using Rails 4 Paperclip and SimpleForm.
I'm trying to make a multiple file upload. For this I am using Dropzone.js upon customer request.
It is a form where I have: Name, Address, Phone, Documents, Certificates.
So I created 2 separate dropzones for documents and certificates.
This is my code on the form:
= simple_form_for(#user, html: {multipart: true, autocomplete: 'off' }) do |f|
= f.input :name, label: false # Column name in table User
= f.input :address, label: false # Column address in table User
#attachments-documents.dropzone # Column document in table User
#attachments-certificates.dropzone # Column certificate in table User
:javascript
var attachments_1 = new Dropzone("div#attachments-documents", { url: "#{upload_file_biddings_path}"});
var attachments_2 = new Dropzone("div#attachments-certificates", { url: "#{upload_file_path}"});
Dropzone.options.attachmentsDocuments = {
paramName: 'user[document]',
maxFilesize: 20,
parallelUploads: 3,
addRemoveLinks : true,
autoProcessQueue: false
}
Dropzone.options.attachmentsCertificates = {
paramName: 'user[certificate]',
maxFilesize: 20,
parallelUploads: 3,
addRemoveLinks : true,
autoProcessQueue: false
}
Controller:
Class User < ApplicationController
[...]
def create
work = Work.new(work_params)
if work.save
flash[:notice] = "Se ha creado correctamente la Obra."
redirect_to :action => :index
else
work.errors.messages.each do |attribute, error|
puts error.to_s
puts error
end
flash[:error] = "Ha ocurrido un error en el sistema."
redirect_to :action => :index
end
end
def update
work = Work.find(params[:id])
if work.update_attributes(work_params)
flash[:notice] = "Se ha actualizado correctamente los datos."
redirect_to :action => :index
else
work.errors.messages.each do |attribute, error|
flash[:error] = attribute " " + flash[:error].to_s + error.to_s + " "
end
# Load new()
#work = work
render :edit, layout: false
end
end
def upload_file
puts params
render :json => params
end
private
def work_params
params.require(:user).permit(:name, :address, :document, :certificate)
end
end
But here I have 2 problems.
1) When I put a file into the Dropzone, by default calls the "upload_file" function when the files should be uploaded when you click on my submit button and GO to create function.
2) I did a test upload multiple files with another JS, however only managed to climb the last of them. Ie:
I put in my file_field 3 files: file1, file2, file3. But in DB, only recorded the file3.
Has anyone uploaded multiple files with Paperclip? Using JS Dropzone.js or other successfully?
If so, I'd like to share knowledge.

render :partial not working as expected

In my index view of products, I have an "Add to cart" that calls javascript function addToCart:
addToCart: function() {
$.ajax({type: 'GET',
url: 'store/add_to_cart/2', // fixed id of product
timeout: 5000,
success: function() { alert('Added !'); },
error: function() { alert('Error !'); }
});
}
def add_to_cart // not working
begin
prod = Product.find(params[:id])
#cart = find_cart
#cart.add_product(prod)
render :partial => 'cart', :object => #cart if request.xhr?
end
end
With this add_to_cart, it renders the partial but also renders the default view for this method - add_to_cart.html.haml -
But if I do it like the following, it renders only the partial.
Could anybody explain me why it is different?
def add_to_cart // working fine
begin
prod = Product.find(params[:id])
#cart = find_cart
#cart.add_product(prod)
if request.xhr?
render :partial => 'cart', :object => #cart
else
redirect_to_index
end
end
end
Thanks for your help !!
The problem is that in that line rails get's confused where are the params for the render call and where is the statement.
You should probably try going like render(:partial => 'cart', :object => #cart) if request.xhr?.
And another thing. If you're using a local variable in the partial, it's better to use locals: {cart: #cart} instead of your :object. Or, if you are following the conventions and that cart partial is in app/view/carts/_cart.html* you can just say render #cart.