Trying to work out this small issue, I have finally got my polymorphic association working but now cant seem to figure out how to show an image in the view once a record has been saved.
My setup
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
attr_accessible :photo
has_attached_file :photo, :styles => { :small_blog => "250x250#", :large_blog => "680x224#", :thumb => "95x95#" }
end
class Post < ActiveRecord::Base
has_many :images, as: :imageable
accepts_nested_attributes_for :images
attr_accessible :comments, :title, :images_attributes
end
So in my view i have this at the moment, which is throwing undefined method 'photo' error
<% #posts.each do |p| %>
<%= image_tag(p.photo.url(:large_blog), :class => 'image') %>
<% end %>
Any pointers appreciated
Post has many images, and each image has a photo. So it can go like this:
<% #posts.each do |p| %>
<% p.images.each do |i| %>
<%= image_tag(i.photo.url(:large_blog), :class => 'image') %>
<% end %>
<% end %>
Related
While i was trying to submit the form, following error occured: Validation failed: Images imageable must exist and render the same new.html.erb view.
If i comment the file field in new.html.erb. Product is being created successfully.
ProductsController:
def new
#product = Product.new
end
def create
#product = Product.create!(product_params)
if #product.save
redirect_to products_path, notice: "Product Created Successfully"
else
render "new"
end
end
def product_params
params.require(:product).permit(:name, :quantity, :price, images_attributes: [:id, :photo, :_destroy])
end
new.html.erb:
<%= nested_form_for #product, html: { multipart: true } do |f|%>
<h2>New</h2>
<P> <%= f.label :name %> <%= f.text_field :name %> </P>
<P> <%= f.label :quantity %> <%= f.text_field :quantity %> </P>
<P> <%= f.label :price %> <%= f.text_field :price %> </P>
<%= f.fields_for :images do |p| %>
<p> <%= p.label :photo %> <%= p.file_field :photo %> </p>
<%= p.link_to_remove "Remove Image" %>
<% end %>
<%= f.link_to_add "Add Image", :images %>
<%= f.submit "Add Product" %>
<% end %>
20160725102038_add_image_columns_to_imageable.rb:
class AddImageColumnsToImageable < ActiveRecord::Migration[5.0]
def up
add_attachment :images, :photo
end
def down
remove_attachment :images, :photo
end
end
Model:product.rb
class Product < ApplicationRecord
has_one :variant
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
Model:image.rb
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
In rails 5, belongs_to makes sure that the associated model must exist.
E.g In this polymorphic association, Image model has belongs_to :imageable and Product model has has_many :images.
So here in new.html.erb we are creating an image, but respective product not exist, so that's why error Image imageable must exist .
Solution
Add optional: true while making an association of belong_to in Image model.
Image Model now looks like:
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true, optional: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
Please help me to solve this error.When update action is executing this error is showing.
Error:
NoMethodError in UsersController#update
undefined method `permit' for :user:Symbol
My code snippets are given below.
views/users/edit.html.erb
<h1>Edit your data</h1>
<%= form_for #user,:url => {:action => 'update',:id => params[:id]} do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field:name,:value => #edit.name %>
<%= f.email_field:email,:value => #edit.email %>
<%= f.text_field:message,:value => #edit.message %>
<%= f.submit "Update" %>
<% end %>
<%= link_to "Back",users_index_path %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_params)
if #user.save
flash[:notice]="Your data is saved succesfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You are entering wrong data"
flash[:color]="invalid"
render :new
end
end
def show
#user=User.all
end
def delete
#user=User.find(params[:id])
if #user.delete
flash[:notice]=#user.name+"has deleted successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]=#user.name+"could not delete.Please check it.."
flash[:color]="invalid"
render :show
end
end
def edit
#edit=User.find(params[:id])
#user=User.new
end
def update
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data has updated successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..check it.."
flash[:color]="invalid"
render :edit
end
end
private
def users_params
params.require(:user).permit(:name, :email, :message,pets_attributes: [:name, :email,:message])
end
def update_params
params.require (:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
end
model/user.rb
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true,:length => { :minimum => 5 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :message, :presence => true
end
Please help me to solve the above error.
You have space between require and (:user). Your current code is equivalent to:
def update_params
params.require(:user.permit(:name,:email,:message,pets_attributes: [:name, :email,:message]))
end
As you can see now, you call permit method on :user symbol and this is direct cause of error.
It should be:
def update_params
params.require(:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
BTW having two methods that do exactly same thing is quite pointless.
Check your question:
you have a space after require and before (:user)
Try:
def update_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
For a better way, you can have just one method:
def user_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
Instead of having separate filter methods for new and edit, you can have just one method and reuse that in both new and edit.
Just keep things Simply DRY.
I am trying to create an article which holds in_prices and out_prices (one for each country) using rails polymorphic associations and nested forms.
I have a data model which looks something like this:
# app/models/article.rb
class Article < ActiveRecord::Base
has_many :out_prices, :class_name => "Price", :as => :priceable
has_many :in_prices, :class_name => "Price", :as => :priceable
end
# app/models/price.rb
class Price < ActiveRecord::Base
belongs_to :priceable, :polymorphic => true
end
# db.schema for prices
create_table "prices", :force => true do |t|
t.integer "value"
t.integer "country_id"
t.integer "priceable_id"
t.string "priceable_type"
end
The article and its associations are created using a nested form like:
# app/views/articles/_article_form.html.erb
<%= form_for setup_article(#article) do |f| %>
<%= f.fields_for :in_prices do |ff| %>
<%= ff.text_field :value %>
<% end %>
<%= f.fields_for :out_prices do |ff| %>
<%= ff.text_field :value %>
<% end %>
<% end %>
The setup_article method is a helper method to build the associations:
# app/helpers/articles_helper.rb
def setup_article(article)
if article.in_prices.nil?
# Setup one in price for each country
Country.all.each do |country|
article.in_prices.build(:value => 0, :country_id => country.id)
end
end
if article.out_prices.nil?
# Setup one out price for each country
Country.all.each do |country|
article.out_prices.build(:value => 0, :country_id => country.id)
end
end
article
end
setup_article is needed to make sure empty price form fields (one for each country) shows up when creating a new article.
Now to the actual problem. When I edit an already created Article (which have associated in_prices and out_prices) Rails won't be able to differentiate between these different types of polymorphic associations (in_prices and out_prices). Because of this both nested form helpers renderes form fields for all associated prices, which isn't the desired behavior. I only want to list in_prices in the one of the nested forms, and the out_prices in the other.
How should these associations be configured to make sure rails can differentiate between the in_prices and out_prices associations in the two different nested form helpers?
EDIT (SOLVED)
A friend of mine pointed out I need to add yet another field in the prices table to flag what type of price it is. I called this field price_type and the db.schema ended up looking like this:
# db.schema for prices
create_table "prices", :force => true do |t|
t.integer "value"
t.integer "price_type"
t.integer "country_id"
t.integer "priceable_id"
t.string "priceable_type"
end
Note: Don't name this field 'type' since this is a reserved name.
The 'price_type' field can be populated either by adding a hidden field in the nested forms (less safe), or to handle it in the controller before saving the article and its associated data. I chose to add it as hidden params like:
# app/views/articles/_article_form.html.erb
<%= form_for setup_article(#article) do |f| %>
<%= f.fields_for :in_prices do |ff| %>
<%= ff.text_field :value %>
<%= ff.text_field :price_type, :value => "in" %>
<% end %>
<%= f.fields_for :out_prices do |ff| %>
<%= ff.text_field :value %>
<%= ff.text_field :price_type, :value => "out" %>
<% end %>
<% end %>
To make sure the associations gets filtered correctly they need to be declared with the ':conditions' tag, like:
# app/models/article.rb
class Article < ActiveRecord::Base
has_many :out_prices, :class_name => "Price", :as => :priceable, :conditions => { :price_type => "in" }
has_many :in_prices, :class_name => "Price", :as => :priceable, :conditions => { :price_type => "out" }
end
.. and now everything works as expected. cheers!
I am trying to make available to upload a multiple pictures with paperclip. I am following this tutorial: http://www.emersonlackey.com/article/paperclip-with-rails-3
Unfortunately I have error:
No handler found for "apple_mac-1280x800.jpg"
Asset.rb
class Asset < ActiveRecord::Base
belongs_to :post
has_attached_file :asset, :styles => { :small => "100x100", :original => '800x600>'}
end
Post.rb
class Post < ActiveRecord::Base
has_many :assets
accepts_nested_attributes_for :assets, :allow_destroy => true
end
Posts_controller.rb
def new
#post = Post.new
5.times { #post.assets.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
def edit
#post = Post.find(params[:id])
5.times { #post.assets.build }
end
#Post form
<% create_url = {:url=>{:action=>"create"}} if #post.new_record? %>
<% form_for #post, :html => {:multipart => true} do |t| %>
<p>
<%= t.label :title, 'Virsraksts:' %>
<%= t.text_field :title %>
</p>
<p>
<%= t.label :content, 'Teksts:' %>
<%= t.text_area :content, :class => "mceEditor"%>
</p>
<%= t.fields_for :assets do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<p>
<%= asset_fields.file_field :asset %>
</p>
<% end %>
<% end %>
<%= t.submit %>
<% end %>
<%end%>
Problem solved by changing
<%= t.fields_for :assets do |asset_fields| %>
to
<%= f.fields_for :assets do |asset_fields| %>
But could someone explain why?
I am trying to create a form that creates a game and game_players at the same time.
The problem I am having is that when I submit the form, the game is created, but the game_players are not.
I've looked around, but haven't found any helpful answers.
Game Model
class Game < ActiveRecord::Base
belongs_to :league
has_many :game_players, :dependent => :destroy
accepts_nested_attributes_for :game_players
attr_accessible :league_id, :game_date
validate :league_id, :presence => true
end
Game_Player Model
class GamePlayer < ActiveRecord::Base
belongs_to :game
has_many :users
validate :game_id, :presence => true
validate :user_id, :presence => true
end
Game Controller
class GamesController < ApplicationController
def new
#title = "New Game"
#game = Game.new
3.times { #game.game_players.build }
end
def create
#game = Game.new(:league_id => cookies[:league_id])
if #game.save
flash[:success] = "Succesfully Created Game"
redirect_to League.find_by_id(cookies[:league_id])
else
#title = "New Game"
render 'new'
end
end
Form
<%= form_for #game do |f| %>
<%= f.fields_for :game_players do |builder| %>
<p>
<%= builder.label :user_id, "User" %><br />
<%= builder.text_field :user_id %><br />
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
most likely you need to pass :game_players_attributes to attr_accessible since .new respect mass-assignment security