I am new to rails and I am trying to work with nested attributes.
The main idea is to have a a deal(offer) model, a deal will have multiple deal_photos from paperclip.
I have already watched Ryan's Railscast for nested forms and read many articles with many tips regarding problems on the same issue but still it doesn't work for me.
Here is my Implementation:
class Deal < ActiveRecord::Base
belongs_to :user
has_many :deal_photos, dependent: :destroy
accepts_nested_attributes_for :deal_photos
end
class DealPhoto < ActiveRecord::Base
belongs_to :deal
has_attached_file :photo, :styles => { :large => "600x170", :medium => "250x250!", :thumb => "100x100>" }, :default_url => lambda { |photo| photo.instance.set_default_url}
def set_default_url
ActionController::Base.helpers.asset_path('missing.png')
end
end
In my deals controller:
class DealsController < ApplicationController
def new_deal
#deal=Deal.new()
#user= User.find(params[:id])
3.times { #deal.deal_photos.build }
end
def create
#deal = Deal.new(deal_param)
#user= User.find(params[:user_id])
if #deal.save
#user.deals << #deal
flash[:notice]="Thank you"
end
end
def edit
#deal=Deal.find(params[:deal_id])
3.times { #deal.deal_photos.build }
end
def update
#deal=Deal.find(params[:id])
if #deal.update_attributes(deal_params)
flash[:notice]="Deal updated successfully"
end
end
private
def deal_params
params.require(:deal).permit(:title, :description, :contact_num, :user_id, :deal_photos_attributes => [ :id, :caption, :photo, :deal_id])
end
Finally in my form for a new deal:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
<label>Title<b style="color:red;">*</b>
<%= f.text_field(:title, :placeholder=>"") %>
</label>
------------more fields---------------------
<%= f.fields_for :deal_photos do |builder| %>
<div>
<%= builder.label :caption, "Image Caption" %>
<%= builder.text_field :caption %>
<%= builder.label :photo, "Image File" %>
<%= builder.file_field :photo %>
</div>
<%end%>
<%= button_tag("Create", :class=> "secondary button", :button_type => "submit") %>
(I have migrated the db for deals_photo to accept paperclip)
The above, creates a form with all fields but instead of 3 inputs for file upload shows only one. It creates 3 empty associations #deal.deal_photos but even if I choose one image to upload from the form it doesn't save it.
If you have any useful advices or another similar question please help!
What's in your deal_param method?
Do you permit deal_photos' attributes in it?
If no then do something like
def deal_params
params.require(:deal).permit(deal_attr1, deal_attr2,...., deal_photos_attributes: [:deal_photo_attr1, ...])
end
Also, do you get a deal_id in your deal_photos in view?
Finally, I was able to solve the problem in the new_deal.html.erb when I replaced the:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
with
<%= form_for(#deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
What is changed is that the second line is for the specific new deal instance. Maybe the reason that the first was not working is that the deal_photos didn't get the deal_id, as Alexphys said. But still I haven't figure out the exact reason.
Related
I have 2 non nested models, User and Record. The goal is to paginate the #user.records called #records at users/show
Here is the Record part:
at app/models/record.rb
class Record < ActiveRecord::Base
default_scope lambda { order('records.created_at DESC') }
paginates_per 48
end
I am using Kaminari at records/index and works great. Problem is to use it at users/show
Here the app/controllers/users_controller.rb
def show
#user = User.find(params[:id])
#records = #user.records.page params([:page])
# Not working alternative:
# #records = #user.records.page(params[:page]).per(48)
end
Here is the view that triggers the display, is the listing rendered inside users/show...
<% #records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<%= paginate #records %>
Errors are very interesting. As it is, error is:
No route matches {:action=>"show", :controller=>"users", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
Meaning paginate #records is building a request to Active Record that hopes to find an action I do not have in that controller (I am using devise). So at Kaminari instructions says is possible to pass the params, like this:
<%= paginate #records, :params => { :controller => 'foo', :action => 'bar' }, :remote => true %>
Then the error becomes like this:
No route matches {:action=>"remote_records_pagination", :controller=>"records", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
I have a remote_recors_pagination defined at records_controller, renders records_paginate_remotely.js, but the pagination method does not find it. Why it keeps showing :controllers registrations?
Finally, to change the view like this:
<%= paginate #user.records %>
<% #user.records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<% end %>
Produces an undefined method error.
Should not the example be working with or without js file? Any help?
Thanks.
I found a solution. I am posting an answer because the problem was on routes and the mix with devise, common combo that more people may find.
So, routes was like this:
devise_for :users
resources :users, only: :show, , :controllers => { :registrations => :registrations } do
member do
get :following, :followers
end
end
To change it to this:
devise_for :users, :controllers => { :registrations => :registrations }
resources :users, only: :show do
member do
get :following, :followers
end
end
allows the paginate command interact with Active Record normally. Devise first test seems ok.
I am trying to implement the acts_as_taggable_on gem. In my set up I have a Model called Discipline which is pre-populated with about 40 names.
I also have a Model Micropost which I want to tag - using a select box containing all the names in the disciplines database. I thought that I could call the acts_as_taggable_on the Model I wanted - in this case Disciplines but its not working with my current set up.
class Micropost < ActiveRecord::Base
acts_as_taggable
acts_as_taggable_on :disciplines
end
Here is the form......
<%= simple_form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.input :tag_list, :as => :select,
:multiple => :true,
:collection => ActsAsTaggableOn::Tag.pluck(:name) %>
<%= f.text_area :content, placeholder: "What is your question?", :style => "height:75px;" %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
I can tell from the documentation that there is a way to do this....but I guess I am just not getting it. Any suggestions?
I don't think you can use acts_as_taggable_on using a model other than the default Tag and Taggings models.
Alternative Approach #1
Seed your database with the pre-populated 40 Tags containing your discipline names.
Alternative Approach #2
Use bitmask_attributes for your 40 disciplines.
For example, in my application I have:
bitmask :instruments, as: [:others, :guitar, :piano, :bass, :mandolin, :banjo,
:ukulele, :violin, :flute, :harmonica, :trombone,
:trumpet, :clarinet, :saxophone, :viola, :oboe,
:cello, :bassoon, :organ, :harp, :accordion, :lute,
:tuba, :ocarina], null: false
I'm using form for and the name of the form in the controller is appearing as "#", but I expect it to appear as :edge.
Here's my controller:
def new
#some_stuff
#edge = Edge.new
#some_stuff
end
def create
#edge = Edge.new(edge_params)
#edge.save
end
def edge_params
params.require(:edge).permit(:location_1_id, :location_2_id)
end
View:
<%= form_for( :edge, :url => {:action => 'create'}) do |f| %>
<ul>
<li>
<%= f.label :location_1_id %>
<%= collection_select(#edge, :location_1_id, #location, :id, :record_as_string) %>
</li>
<%= submit_tag(t(:create_edge)) %>
</ul>
<% end %>
Param req:
{"utf8"=>"✓", "authenticity_token"=>"blah",
"#"=>{"location_1_id"=>"91", "location_2_id"=>"92"},
"commit"=>"Create Edge", "action"=>"create",
"controller"=>"admin/edges", "floor_map_floor_id"=>"1"}
So the name of the parameter should be :edge but it's an object that I can't access.
Can anybody tell me what I'm missing?
Any help is appreciated.
You should be using the form block on your collection set like so
<%= f.collection_select(:location_1_id, #location, :id, :record_as_string) %>
(notice that you are calling the collection_select on the block variable f, and NOT passing in the #edge as the first argument).
In addition, because you are creating the object in new (#edge = Edge.new), you should just be using in your form, like so
<%= form_for( #edge, :url => {:action => 'create'}) do |f| %>
(although using :edge wasn't the cause of your problems, I suspect it was because you were using :edge and #edge in the same form. You need to be consistent, use one or the other)
I have a rails app where users can upload pins, I want to use the [acts_as_commentable_gem][1] to allow users to comment pins, here is my config:
app/models/pin.rb
class Pin < ActiveRecord::Base
acts_as_commentable
end
app/controlers/pins_controller.rb
def show
#pin.find params[:id]
#comment = #pin.comments.new
end
app/views/pins/show.html.erb
<%= form_tag "/pins/add_new_comment" do %>
<%= hidden_field_tag "id", post.id %>
<%= text_area_tag "comment[comment]" %>
<%= submit_tag "Pin Comment" %>
<% end %>
app/models/comment.rb
class Comment < ActiveRecord::Base
include ActsAsCommentable::Comment
belongs_to :commentable, :polymorphic => true
default_scope -> { order('created_at ASC') }
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_voteable
# NOTE: Comments belong to a user
belongs_to :user
end
app/controllers/pin_controller.rb
def add_new_comment
pin = Pin.find(params[:id])
pin.comments << Pin.new(params[:comment])
redirect_to :action => :show, :id => pin
end
finally in my config/routes
get "/pins/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins", :via => [:pin]
But I run to a routing error:
undefined local variable or method `acts_as_commentable' for PinsController:Class
I am really not sure where this error come from, any ideas?
I am not really sure but you route shouldn't be like
get "/pins/:id/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins"
If Project has_many Genre through: GenresProject
and params are:
def project_params
params.fetch(:project, {}).permit(genres_projects_attributes: [:id, {genre_id: []})
end
and my submit form is:
<%= form_for #project do |f| %>
<%= f.fields_for :genres_projects_attributes do |ff| %>
<%= ff.select :genre_id, Genre.order(:id).collect{|g| [g.name, g.id]}, {}, { multiple: true } %>
<% end %>
<%= f.submit 'Update'%>
<% end %>
and my params look like this:
"project"=>{ ... "genres_projects_attributes"=>{"genre_id"=>["3", "5"]}} ... }
Should
project.update(project_params)
Automatically iterate through the genre_id array and create the appropriate GenresProject records?
If you don't have GenreProject record, then you will not get an id from the params.
Secondly, it will not automatically create the new Genre record or update one for you, I think. You should handle creating new record in the update action yourself. For example:
params[:project][:genre_id].each do |id|
unless GenreProject.find(id)
# create new record here
GenreProject.create
end
# other updating operations
end
Hope it works for you