A better way to get paperclip thumbnail in index.html.erb - ruby-on-rails-3

I've been struggling with this for hours. For some background, I have paperclip set up, keeping in mind that I may one day want to add multiple attachments. I followed Emerson's screencast to help me figure it out. (http://www.emersonlackey.com/article/paperclip-with-rails-3)
I now have this in my view, which shows what I want it to show. I had trouble for a long time because it was kicking up errors when a thumbnail didn't exist for some posts.
Anyway, wrote it, it's in my view, and I just think it's really ugly. I feel like I must be missing something. For one thing, I'm completely repeating myself on one line. Secondarily, I've got this code in my view. Is there something that I should be doing in my controller to help me keep my view cleaner?
Thanks a bunch!
<% if Asset.where(:piece_id => piece.id).first
my_asset = Asset.where(:piece_id => piece.id).first%>
<%= piece.id%>
<%= image_tag my_asset.asset.url(:thumb)%>
<% end%>
Because I haven't done anything to my controller to speak of, I'm leaving all of that code out. But here's what my models look like:
Assets
class Asset < ActiveRecord::Base
belongs_to :piece
has_attached_file :asset, :styles => {:large => ['700x700', :jpg], :medium => ['300x300>', :jpg], :thumb => ["100x100>", :jpg]}
end
Pieces
class Piece < ActiveRecord::Base
attr_accessible :assets_attributes,:name, :campaign_id,:election_date, :mail_date, :pdf_link, :photo_desc, :photo_stock, :killed, :format, :artist
belongs_to :client
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
validates :campaign_id, :presence => true
end

So your problem is that sometimes a Piece has a thumbnail and sometimes it doesn't, right?
I'd agree that your ERB solution smells bad. You could add a thumb_nail_url method to Piece:
def thumb_nail_url
asset = assets.first
asset ? asset.asset.url(:thumb) : nil
end
And then:
<% thumb_url = piece.thumb_nail_url %>
<% if thumb_url %>
<%= image_tag thumb_url %>
<% end %>
You could also wrap the above in a helper:
def piece_thumb_image_tag(piece)
thumb_url = piece.thumb_nail_url
thumb_url ? image_tag(thumb_url) : ''
end
and then:
<%= piece_thumb_image_tag piece %>

Related

How to create new records with nested attributes in a ruby on rails "has many through" relationship?

I need some advice on building a has many through relationship between USER, THING and EXTRA models.
My USER model is slightly modified inside Devise gem and is noted as Creator whereas other models belonging to USER receive :created_things form.
In my app, USERS create THINGS can later add EXTRAS to their THINGS.
I chose has many through because I want to have unique data on all three models and be able to call both THINGS and EXTRAS from the USER "CREATOR" model.
I have built this many different ways and after 10 years of solving my problems by reading stackoverflow, I am finally submitting this request for support! Thank you for your help.
I have tried creating user and extra references on the THING model and declaring nested attributes in the USER and THING model. I have tried several examples from stackoverflow inside the create and new methods but nothing seems to work.
class User < ApplicationRecord
has_many :created_things, class_name: Thing, foreign_key:
:creator_id, :dependent => :destroy
has_many :extras, through: :created_things
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Extra < ApplicationRecord
belongs_to :creator, class_name: User, inverse_of: :thing
belongs_to :created_things
Members Index.html.erb
<% if thing.extras.exists? %>
<% thing.extras.each do |extra| %>
<%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
<% end %>
<% else if thing.extras.empty? %>
<%= link_to "+1 EXTRA", new_extra_path(current_user) %>
<% end %>
<% end %>
class MembersController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#created_extras = #user.extras
#created_things = #user.created_things
end
class ExtrasController < ApplicationController
def new
#extra = Extra.new
end
def create
#extra = current_user.extras.build(extra_params)
if #extra.save
I am able to create a new EXTRA but the :thing_id remains nul as it does not display when called on the show extra view. Therefore I am not surprised that when I return to the member index page that my thing.extras.exists? call is returning false and the created extra never displays under the THING view. My attempts to modify the extra controller have failed and I some of my reading sugested the extras controller is not necessary in this relationship so I am really at a loss on how this is built. I'm assuming I am missing something in new and create methods maybe in things or user controller? Perhaps I'm missing something in routes resources? Any advice is greatly appreciated. Thank you.
Ok, I figured it out. I really didn't need has many through for this model and I did a lot of testing of the syntax on each model.rb and in the end was able to figure it out from this stackoverflow . . .
[Passing parent model's id to child's new and create action on rails
Here are my the various parts of setting up a has many and belongs to relationship with nested attributes.
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras, inverse_of: :thing, :dependent => :destroy
accepts_nested_attributes_for :extras, allow_destroy: true
class Extra < ApplicationRecord
belongs_to :thing, inverse_of: :extras
extras_controller.rb
class ExtrasController < ApplicationController
def new
#extra = Extra.new(thing_id: params[:thing_id])
end
def create
#user = current_user
#extra = Extra.new(extra_params)
#extra.user_id = #user.id
if #extra.save
flash[:success] = "You have added a new Extra!"
redirect_to #extra #extras_path later
else
flash[:danger] = "The form contains errors"
render :new
end
end
edit.html.erb things
<% if #thing.extras.exists? %>
<p>current extras associated with <%= #thing.title %>: </p>
<% #thing.extras.each do |extra| %>
<p><%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
/ <%= link_to "[-]", extra_path(extra), method: :delete %> </p>
<% end %>
<% end %>
<%= link_to "+1 EXTRA", new_extra_path(thing_id: #thing.id) %>
<%= render 'things/form' %>

rails 3 how to associate a new object without mass-assign error

I came back to the relatively "old book" Head First rails, which was published for Rails 2.3.
Now, going back again through those samples and using Rails 3 I came up with some questions.
Let's say that I'm adapting the sample for coconut airways and instead of flights and seats, I have a project and tasks.
The page shows a project description and below a list of tasks associated to that project. so far so good. now below that there is a form to create new task. This task needs a Task object and the project_id. here is when things do not work as before.
if you want to do it like the old style you will type:
<%= render :partial => "new_task",
:locals => {:task => Task.new(#project.id)} %>
well, this is showing the mass-assign error.
Then I tried to pass both as parameter:
<%= render :partial => "new_task",
:locals => {:task => Task.new, :project_id => #project.id} %>
and assign it in the partial
<%= f.hidden_field :project_id, :value => project_id %>
any hint?
EDITED:
class Task < ActiveRecord::Base
belongs_to :project
attr_accessible :title
end
class Project < ActiveRecord::Base
has_many :tasks
attr_accessible :description, :title
end
If you change your model's attr_accessible you can include these assignments to be made. For more information about attr_accessible and mass assignment see: Ruby on Rails API

Rails 3 polymorphic association with Carrierwave and Simple Form

I'm trying to set up a polymorphic association for photo uploads which are processed using Carrierwave. I'm using Simple Form to build my forms. I feel like the association is correct so I'm wondering if my problem is just something with the form or controller.
Here are my associations:
property.rb:
class Property < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
...
end
unit.rb
class Unit < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
end
image.rb
class Image < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
mount_uploader :image, PhotoUploader
end
properties_controller.rb:
def edit
#property = Property.find params[:id]
#property.image.build if #property.image.empty?
end
def update
#property = Property.find params[:id]
if #property.update_attributes params[:property]
redirect_to admin_properties_path, :notice => 'The property has been successfully updated.'
else
render "edit"
end
end
Snippet from properties/_form.html.erb
<%= f.input :image, :label => 'Image:', :as => :file %>
Here is the error I get when submitting with an image attached:
undefined method `each' for #<ActionDispatch::Http::UploadedFile:0x00000102291bb8>
And here are the params:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"lvB7EMdc7juip3gBZD3XhCLyiv1Vwq/hIFdb6f1MtIA=",
"property"=>{"name"=>"Delaware Woods",
"address"=>"",
"city"=>"",
"state"=>"",
"postal_code"=>"",
"description"=>"2 bedroom with large kitchen. Garage available",
"incentives"=>"",
"active"=>"1",
"feature_ids"=>[""],
"user_ids"=>[""],
"image"=>#<ActionDispatch::Http::UploadedFile:0x00000102291bb8 #original_filename="wallpaper-4331.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"property[image]\"; filename=\"wallpaper-4331.jpg\"\r\nContent-Type: image/jpeg\r\n",
#tempfile=#<File:/tmp/RackMultipart20120608-3102-13f3pyv>>},
"commit"=>"Update Property",
"id"=>"18"}
I'm looking everywhere for help on polymorphic associations and am getting nowhere. I've seen simple examples that look pretty straight forward. One thing I've noticed is that it seems like in a lot of the examples the has_many association in my case should be images and not image. However when I do that I get an error:
Can't mass-assign protected attributes: image
I've tried updating my form to use fields_for as I've seen in other blogs like so:
<%= f.input :image, :label => "Photo", :as => :file %>
<% f.simple_fields_for :images do |images_form| %>
<%= images_form.input :id, :as => :hidden %>
<%= images_form.input :attachable_id, :as => :hidden %>
<%= images_form.input :attachable_type, :as => :hidden %>
<%= images_form.input :image, :as => :file %>
<% end %>
All I know is I'm having a heck of a time getting this to work. I'm pretty new to Rails so even debugging it is difficult. It doesn't help that the debugger doesn't really work in 3.2 :(
Since your models have_many :images (it should be :images, not :image), you'll want to use nested_forms in your views. You should set up accepts_nested_attributes_for :images on the unit and property models and change the attr_accessible from :image to :image_attributes.
Check out http://railscasts.com/episodes/196-nested-model-form-part-1 for a good guide on getting going with it.

Rails best_in_place gem with nested resource

Does anyone know if it is possible (and, if so, what the syntax is) for using a nested resource with the best_in_place gem?
My routes.rb looks something like this
resources :users do
resources :goals
end
I would like to edit the :description field of the goal, but the code in my view for
<%= best_in_place [#user, #goal], :description %>
gives a NoMethodError saying
undefined method `description' for #<Array:0x20e0d28>
Using
<%= best_in_place #goal, :description %>
give me an undefined method error also because there is no goal_path
I can get the gem to work for #user (the non nested resource) field without problems.
I'm running Rails 3.1.1, Ruby 1.9.2, best_in_place 1.0.4
I figured it out.
I needed to set the path option in the call like so
<%= best_in_place #goal, :description, :path => user_goal_path %>
It works like a champ now!
Add path and the objects to the path:
<%= best_in_place #goal, :description, :path => user_goal_path(#user,#goal) %>
Somehow the simple path solution of bknoles didn't work for me.
Now above method is deprecated.
According to latest Documentation use ":url" instead of ":path" like below in the example
<%= best_in_place #goal, :description, :url => user_goal_path %>
Cheers!
Thank you, #bknoles. Your answer definitely helped me reach a similar solution of my own. Here's my implementation:
#widget.rb
class Widget < ActiveRecord::Base
validates_presence_of :name
has_many :gadgets
attr_accessible :name, :description
end
#gadget.rb
class Gadget < ActiveRecord::Base
belongs_to :widget
attr_accessible :name, :widget_id, :id
end
#gadgets_controller.rb
def update
#gadget=#widget.gadgets.find(params[:id])
if #gadget.update_attributes(params[:gadget])
respond_to do |format|
format.html
format.json { respond_with_bip(#gadget) }
end
else
respond_to do |format|
format.html { render :action => "edit" }
format.json { respond_with_bip(#gadget) }
end
end
end
#views/gadgets/_gadget.html.haml
%tr{ :name => "gadget_", :id => gadget.id }
%td= gadget.created_at.localtime.strftime("%B %d, %l:%M%p")
%td.big=best_in_place gadget, :name, :path => [#widget, gadget]
%td.delete{:style => 'text-align:center;'}
=check_box_tag "gadget_ids[]", gadget.id, false, :class => "checkbox"
You can checkout the entire project on github if you want to see more of the code.
https://github.com/hernamesbarbara/ajax-rails-full-crud
Best,
Austin

Can't mass-assign protected attributes:

I have pulled out all my hair. No more left... :(
I am using Spree 0.3.4, within an extension I need to register some retailers up. so I direct them to a retailers form which has many custom fields which belong to a retailer model...
So I am trying to validate/submit all the fields from one form like so
myextension/app/views/user_registrations/new.html.erb
<%= form_for (:user, :url => registration_path(#user, :type => "retailer) do |f| %>
<%= f.fields_for :retailer do |r| %>
<%= r.text_field :name %>
<% end %>
<%= f.text_field :email %>
<% end %>
etc etc
class Retailer < ActiveRecord::Base
belongs_to :user
validates :name,
:presence => true
end
class User < ActiveRecord::Base
has_one :retailer
accepts_nested_attributes_for :retailer
attr_accessible :retailer_attributes
# theres a whole lot more spree and devise stuff here. not sure worth mentioning
end
I have also added the abilities in the cancan ability.rb
The problem is the retailer feilds never get validated and the data is never inserted into the database...
I created a blank app, and tried this process from scratch with some plain old scaffolding and it works fine.
any ideas??
In your application helper, do something like this(assuming your have Ruby 1.9.* for the tap functionality, otherwise checkout rails returning here):
def setup_user(user)
user.tap do |u|
u.build_retailer if u.retailer.nil?
end
end
then in your view change it to this:
<%= form_for (setup_user(#user), :url => registration_path(#user, :type => "retailer) do |f| %>
See if that works.