Rails 3.1 RC4 remove_attachment doesnt remove! - ruby-on-rails-3

Using Carrierwave 0.5.4 on Rails 3.1 RC4.
In Rails console, I do:
#foo.attachment
returns:
=> http://cdn.site_name.com/uploads/users/2/banners/banner.png
However:
#foo.remove_attachment!
returns:
=> [:remove_versions!]
The record still remains in the DB, BUT the file is removed in the S3 bucket.
What is going on?

Ahhh, after further investigating. This is what I have found out. remove_attachment! is meant to remove the image from S3, but is not meant to remove the uploader object in the attachment column, in the db. This is the normal behavior of Carrierwave.
Jnicklas provided a test spect at https://github.com/jnicklas/carrierwave/commit/ecabc618d0fce22c1931c6d2eb134886e3b60e4c which uses #doc.remove_image = true. This is the key, because when one submits a form to remove an attachment / image / photo / whatever. They normally include a check box that looks like:
<input type="checkbox" value="1" name="user[remove_attachment]" id="user_remove_attachment">
Which can be rendered with the helper tag as:
<%= f.check_box :remove_attachment %>
If the check box is clicked and the form is submitted. Params will look something like:
{"utf8"=>"✓", "_method"=>"put", ....., "user"=>{"remove_attachment"=>"1"}, "controller"=>"das....}
Rails will interpret this as #user.remove_attachment = true to clear the db column and also trigger .remove_attachment! to remove the file from S3.
Also worth noting. If attr_accessible is defined in the User model. Then it must have :attachment, :remove_attachment as well.
Hope this helps someone out.

Related

Access CarrierWave image url using SQL in Rails migration

I'm working on a small app that uses CarrierWave for image uploading, but (for reasons that are a bit long and not really relevant) we have to stop using CarrierWave and start uploading images with our own custom requests to different cloud storage services.
But I still need to have the URLs to images that were already uploaded using CarrierWave, and I won't have access to the image_url method once I unmount the CarrierWave uploader, so I want to save all the urls to a new column on my model, and to have that migration be as optimized as possible.
I've searched for ways to access directly the url from the database (I mean, CarrierWave has to store that somewhere) but no luck so far.
I could do something like this (business_image is the column that the uploader is mounted on, image_url is the new column where I want to store the url):
def change
add_column :business_cards, :image_url, :string
BusinessCard.all.each do |bc|
bc.update(image_url: bc.business_image_url)
end
end
But that is obviously not optimized at all since it loads all business cards and updates them one by one. Is there a way to do it in a single SQL statement?
(I'm using Rails 5.1.4, PostgreSQL 10.3 and carrierWave 1.2.1)
One way would be too use batch function and update record in batches, you can use transaction so that if there are any errors the changes would be rolled back.
def change
add_column :business_cards, :image_url, :string
BusinessCard.find_each(batch_size: xxx) do |bc|
ActiveRecord::Base.transaction do
bc.update(image_url: bc.business_image_url)
rescue => e
raise ActiveRecord::Rollback
end
end
end
Hope it helps!!

Rails 3 form actions and methods

I have made a resource.
resources :dashboards
I have a partial file which contains a form and I want to use this partial (as the form elements won't change) to update and create. So here is what I have:
Controller
class DashboardsController < ApplicationController
def new
#dashboard = Dashboard.new
end
end
View
/dashboards/new.html.erb
<%= render :partial => "form", :locals => { :dashboard => #dashboard } %>
Partial Form
/dashboards/_form.html.erb
<%= form_for(#dashboard) do |form| %>
.....
<% end %>
Ruby Guide
The Ruby Guide states:
The Article model is directly available to users of the application, so — following the best practices for developing with Rails — you should declare it a resource. When dealing with RESTful resources, calls to form_for can get significantly easier if you rely on record identification. In short, you can just pass the model instance and have Rails figure out model name and the rest. For example:
## Creating a new article
# long-style:
form_for(#article, :url => articles_path)
# same thing, short-style (record identification gets used):
form_for(#article)
## Editing an existing article
# long-style:
form_for(#article, :url => article_path(#article), :html => { :method => "put" })
# short-style:
form_for(#article)
Result
I thought I have followed the Rails Guide correctly. Because I made #dashboard a resource. I could just pass it into the form and have it handle the action, method and the rest. Instead I'm getting this:
<form accept-charset="UTF-8" action="/dashboards" class="new_dashboard" id="new_dashboard_" method="post">
According to the docs. Shouldn't the action of my form now be "/dashboards/new" because we are on the new action? And should it be passing an extra field declaring the method to be put when I use the same code in the /edit action??
My result is always the same no matter what. The form never changes.
What am I doing wrong?
EDIT
Here is my router info from rake routes
GET /dashboards(.:format) dashboards#index
POST /dashboards(.:format) dashboards#create
GET /dashboards/new(.:format) dashboards#new
GET /dashboards/:id/edit(.:format) dashboards#edit
GET /dashboards/:id(.:format) dashboards#show
PUT /dashboards/:id(.:format) dashboards#update
DELETE /dashboards/:id(.:format) dashboards#destroy
You are correct that you should be able to "pass #dashboard into the form and have it handle the action, method and the rest." The issue here is what new is in the context of RESTful actions.
When you declare a set of resources with resources :dashboards, you are creating a set of routes which map requests to controller actions:
GET /dashboards index
GET /dashboards/new new
POST /dashboards create
GET /dashboards/:id show
GET /dashboards/:id/edit edit
PUT /dashboards/:id update
DELETE /dashboards/:id destroy
You can check this if you run rake routes.
The issue here is that the new action is defined as a GET request to the path /dashboards/new, i.e. this is the route for the form itself. The URL in the action attribute of the actual form is something else: this is where the form will post the data to with a POST request, which on the server (rails) side will map to the create controller action.
When you use the form helper with form_for(dashboard), a form is created with a route corresponding to what dashboard is: if it is a new record (i.e. it does not yet exist in the database), then the form action will be create (and point to /dashboards), whereas if it already exists it will point to the actual URL for the record (e.g. /dashboards/123). This is what makes the form helpers so useful.
So, to sum up, /dashboards is the correct URL, not for the new action but for the create action, which the form helper uses because dashboard is a new record. new is the route to the page where the form resides, i.e. /dashboards/new.
Hope that makes sense.
p.s. as a side note, you shouldn't be accessing #dashboard in the partial if you are passing it in as a local (:locals => { :dashboard => #dashboard }). Just use dashboard.

Pass local rails variable to javascript to partial

I'm giving up my search, I normally try to figure these things out on my own but I'm struggling hard and I just want this to work
I have the link_to seen below where #puser is the user of the profile I'm currently viewing.
<%= link_to 'Request', new_or_edit_relationship_path(nil), :remote => true, :locals => { :puser => #puser} %>
This in turn calls new_relationship_path which is a .js.erb file seen below
alert("<%= escape_javascript(puser.id) %>")
Why won't this work!? It's saying the puser variable or method is undefined. This works perfect if I was to just render a partial passing in the locals but no. Javascript doesn't want to play nice
Could anyone help explain why me or the program is stupid?
When you do a link_to as remote, the user is starting an entirely new request when they click the link. So passing a local means nothing to the new request. (The local doesn't exist any more on the new request.)
So in order for the #puser to exist on the new request, you need to pass the id for that #puser via the URL (whatever you have going on for new_or_edit_relationship_path). The new request needs to look up the puser by that id, and then it can use it in the JS alert().
Hope that helps and is a little clearer than mud.

Showing Link in Text Field in Rails

In my Rails 3.1 app, I have a text field for comments and I want to be able to allow people to include clickable links (instead of just the url showing as plain text), as well as having the text field recognize when a user had line breaks in their text field (without the user adding html). How can I do this?
This works for showing a link if a user puts the html for a href:
<%= simple_format(#user.description) %>
And this works for recognizing and displaying the line breaks from carriage returns in the text_field:
<%= h(#user.description).gsub(/\n/, '<br/>').html_safe %>
However, I haven't figured out how to do both, together.
How about this?
#Doesnt work in this case
#<%= simple_format( h(#user.description).gsub(/\n/, '<br/>') ).html_safe %>
EDIT:
Seems like you need auto_link function to achieve this. Though it is removed from rails 3.1 it is available as a gem. So if you are using rails 3.1 or later you need to get this from a separate gem
#in Gemfile
gem "rails_autolink", "~> 1.0.9"
#in application.rb
require 'rails_autolink'
#Run
bundle install
#now in you view use it like
<%= h auto_link(simple_format(text)) %>
auto_link not only converts urls but also email addresses in clickable link. Get the document here.
Reference Links:
http://rubygems.org/gems/rails_autolink
http://apidock.com/rails/ActionView/Helpers/TextHelper/auto_link
Use the Rinku Gem
Link is here.
It brilliantly solves the problem. Enjoy!

Paperclip not saving files with save()

I have a little problem with paperclip saving the data passed through the form...
If I'm trying to save the record with .save() it won't save.. When I look in the server/log there are no errors or warnings for the paperclip gem :-/
# trying to save the record with save() -- not working :-/
def create
#baan_import = BaanImport.new(params[:baan_import])
if #baan_import.save
redirect_to(baan_imports_url)
else
render 'new'
end
end
Server-log: (using .save() in controller)
https://gist.github.com/1327347
I just don't get it why it's working if I'm using .create instead of .save()
# trying to save the record with Model.create() -- working!
def create
#baan_import = BaanImport.create(params[:baan_import])
redirect_to(baan_imports_url)
end
Server-log: (using .create() in controller)
https://gist.github.com/1327359
Can some one explain me why it's working with create and not with save??
Thanks,
Michael
Can you show us the BaanImport model. My first guess is you're possibly missing baan_upload in attr_accessible on your model, and as a result, Rails will not let you mass assign the file parameter for upload.
Can you also confirm (would appear as though it's properly set up) that your form has html => {:multipart => true} as an option?