I have a polymorphic relationship between Attachments and Users & Teams so that both users and teams can upload attachments. The :team_id or :user_id is passed along as a param when the "Add file" button is clicked. Then, a hidden field in the attachments#new form tells the controller if the request is coming from a Team or User so that attribute_update can be applied to the proper model. In practice, however, the team request is being delivered as user subaction and vice versa. Any ideas as to what may be going wrong?
class Attachment < ActiveRecord::Base
belongs_to :upload, polymorphic: true
end
class User < ActiveRecord::Base
has_many :attachments, as: :upload
end
class Team < ActiveRecord::Base
has_many :attachments, as: :upload
end
team#show
<%= link_to "Add Files", new_attachment_path(:team_id => #team.id), class: "btn btn-md" %>
user#show
<%= link_to "Add Files", new_attachment_path(:user_id => current_user), class: "btn btn-md" %>
attachments#new
<% provide(:title, 'Add file') %>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#attachment) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.file_field :file %>
<% if request.path == new_attachment_path(params[:team_id]) %>
<%= hidden_field_tag(:subaction, 'Team') %>
<% elsif request.path == new_attachment_path(params[:user_id]) %>
<%= hidden_field_tag(:subaction, 'User') %>
<% end %>
<%= f.submit "Add Files", class: "btn btn-primary" %>
<% end %>
</div>
</div>
attachment controller
def create
#attachment = Attachment.create(attachment_params)
#team = Team.find_by(params[:team_id])
#user = User.find_by(params[:user_id])
if #attachment.save
if params[:subaction] == 'Team'
#attachment.update_attribute(:upload, #team)
flash[:success] = "Team file uploaded!"
redirect_to #team
elsif params[:subaction] == 'User'
#attachment.update_attribute(:upload, #user)
flash[:success] = "User file uploaded!"
redirect_to current_user
end
else
render 'new'
end
end
I think the problem is with your if statement in attachments#new. Both params[:team_id] and params[:user_id] would return an integer so your if statement can't really tell if the request is coming from a team or a user. As a suggestion you could store your params[:team_id] in a variable such as #team_id and then change your if statement to something like this:
<% unless #team_id.nil? %>
<%= hidden_field_tag(:subaction, 'Team') %>
<% else%>
<%= hidden_field_tag(:subaction, 'User') %>
<% end %>
However you may be able to improve this further by using polymorphic associations in your models as outlined in the following link: https://launchschool.com/blog/understanding-polymorphic-associations-in-rails
Changed the url param to pass the string 'User' or 'Team' instead of the team_id or user_id allowing the controller if statement to function properly.
Team#show
<%= link_to "Add Files", new_attachment_path(:upload_type => 'Team'), class: "btn btn-md" %>
User#show
<%= link_to "Add Files", new_attachment_path(:upload_type => 'User'), class: "btn btn-md" %>
Attachments#new
<% provide(:title, 'Add file') %>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#attachment) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.file_field :file %>
<%= hidden_field_tag(:subaction, params[:upload_type]) %>
<%= f.submit "Add Files", class: "btn btn-primary" %>
<% end %>
</div>
</div>
Related
I've been able to autofill my text field tags but if i hide them by doing <% instead of <%= they dont save to my database any suggestions?
<%= #low["lowest_price"] %>
<%= form_tag "/bids", method: :post do %>
<div>
<%= label_tag :bid, "place your bid " %>
<%= text_field_tag :bid %>
</div>
<div>
<% label_tag :event %>
<% text_field_tag :event_id, params[:id] %>
</div>
<div>
<% label_tag :user_id %>
<% text_field_tag :user_id, current_user.id %>
</div>
<div>
<%= label_tag :lowest_price %>
<%= text_field_tag :lowest_price, #low["lowest_price"] %>
</div>
<%= submit_tag "Submit" %>
<% end %>
Heres the create action in the bid controller that this form is connected to
def create
#bidd = Bid.new(event_id: params[:event_id], user_id:
params[:user_id], bid: params[:bid], lowest_price:
params[:lowest_price])
if session[:user_id] == current_user.id
#bidd.save
flash[:success] = "bid created."
redirect_to "/users/#{current_user.id}"
else
flash[:warning] = 'please sign in'
redirect_to '/login'
end
heres the page the user show page where the bids will show up on which works as i said when text fields are added manually.
<% #bidds.each do |a| %>
<p>event: <%= a.event_id %></p>
<p>Price: <%= a.bid %></p>
You can use a hidden field.
<%= hidden_field_tag :event_id, params[:id] %>
However I would not use a hidden field for your current_user.id, that is very bad practice and you have access to that in your session already.
I have a User model and Todo model. I want to be able to add multiple todos using a single form.
Routes:
# Users
resources(:users) do
resources(:todos)
end
User model:
class User < ApplicationRecord
has_many :todos
....
Todos controller:
class TodosController < ApplicationController
def new
#user = User.find(params[:id])
#todos = Array.new(10) {#user.todos.build}
end
....
View for todos/new:
<%= form_for([#user, :todos]) do |f| %>
<% #todos.each do |todo| %>
<%= f.text_field(:name, class: "form-control") %>
<% end %>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
What I get is:
undefined method `model_name' for :todos:Symbol
What am I doing wrong? I searched SO for doing multiple saves using one form, and I found this.
I believe you are looking for nested forms.
In your model you will add
accepts_nested_attributes_for :todos
and in your view
<%= form_for #user do |f| %>
TODO:
<ul>
<%= f.fields_for :todo do |todo| %>
<li>
<%= todo.label :todo %>
<%= todo.text_field :todo %>
</li>
<% end %>
</ul>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
in controller
def new
#user = User.find(params[:id])
10.times {#user.todos.build}
end
for refference http://guides.rubyonrails.org/form_helpers.html#nested-forms
NOTE: this code is untested
In your view, try
<%= form_for([#user, #user.todos]) do |f| %>
I'm also new to ruby but hopefully it works.
I have a model called account which has_many :options. I want to create a form in which i can list all the options with a checkbox at the side, so the current account can select the options he/she wants inside a form so I can create the has_many relation.
This is what i have
def index
#account = current_account
#options = ['Op 1', 'Op 2', 'Op 3', 'Op 4']
end
and for the view:
<%= form_for(#account, url: options_path) do |f| %>
<% #options.each do |op| %>
<div class="checkbox">
<%= f.check_box(?????, {:multiple => true}, op, nil) %>
</div>
<% end %>
<%= f.submit class: 'btn btn-default' %>
<% end %>
This is obviously not working and I'm pretty sure this is not the right way to achieve what I want to do, so any help would be appreciated.
You could use fields_for:
<%= form_for(#account, url: options_path) do |f| %>
<%= fields_for :options do |options_form| %>
<% #options.each do |option| %>
<div class='checkbox'>
<%= options_form.label option do %>
<%= options_form.check_box option %> <%= option %>
<% end %>
</div>
<% end %>
<% end %>
<%= f.submit class: 'btn btn-default' %>
<% end %>
And in your params, you will get values like: params[:account][:options]['Op1'] with value '1' for true and '0' for false.
I'm new to Ruby on Rails, and I'm looking create a system where users join a house, and then can leave notes to other users in their house. Each note should have individual permissions per other users in their house. When a user creates a note, they will be greeted with a form with a text area for the Note content, and then a list of all the other users in the house, with a dropdown indicating that users level of permission on that note.
I'm attempting to use Partials to make things nicer, as Permissions are a polymorphic class and will be used in other parts of our website. Right now, when a Note is submitted as a new note, only one Permission is being POSTed, instead of a Permission for each user, e.g.
Started POST "/notes" for 127.0.0.1 at 2015-11-03 11:37:47 -0500
Processing by NotesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8+fSG6oBsp4C3ikKc6mSNQYIB+mM5w3+42Y5tRVi5LOZY4a1lo0EApLo0WtSVNZ6/MO0yRwGitZzgZWaYR23mg==", "note"=>{"content"=>"okay...", "permissions_attributes"=>{"0"=>{"user_id"=>"0", "level"=>"3"}}}, "commit"=>"Post"}
I've spent a while comparing my View code with partials to others, and can't figure out why it's not submitting a permission for each user. Any advice? I can confirm that the permission that is submitted is created in the NoteController and created in the database correctly. It's just that instead of creating a permission for each user in the list, it's only creating the default permission.
Note Creation GUI
_form.html.erb
<%= form_for(#note) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new Note..." %>
</div>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission_new', :f => perm %>
<% end %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
_permission_new.html.erb
<% House.find(current_user.relationship.house_id).users.each do |user| %>
<%= render 'permission', :f => f, user: user %>
<% end %>
<% User.new(id: 0) do |user| %>
<%= render 'permission', :f => f, user: user %>
<% end %>
_permission.html.erb
<% if current_user.id != user.id %>
<div class="permission">
<% if user.id == 0 %>
Default Permission
<% else %>
<%= user.name %>
<% end %>
<%= f.hidden_field :user_id, value: user.id %><br />
<%= f.select :level, [["Read Only", 3], ["Read, Edit, and Delete", 1],
["Read and Edit", 2], ["Can't Read", 4]] %>
</div>
<% end %>
note_controller.rb
...
def new
#note = Note.new
#note.permissions.build
end
def create
#note = current_user.notes.build(note_params)
if #note.save
#perm_user = #note.permissions.create(user_id: current_user.id, level: 0)
flash[:success] = "Note Created"
redirect_to notes_path
else
render 'new'
end
end
...
private
def note_params
params.require(:note).permit(:content, permissions_attributes: [:user_id, :level])
end
In case anyone happens to be having the same problem, I figured it out.
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission_new', :f => perm %>
<% end %>
f.fields_for only technically creates one field per call. This means that in my _permission_new.html.erb file, where I have a loop creating a dropdown for each user in the house, and a dropdown for the default, all of those dropdowns were linked to the same field, and overwriting each other. Which is why only the last permission was being POSTed when a new Note was submitted. To fix this, you must call the f.fields_for multiple times in your form. In my case, I moved my f.fields_for into my _permission_new partial, and ended up with code like this.
_form.html.erb
...
<%= render 'permission_new', f: f %>
...
_permission_new.html.erb
<% House.find(current_user.relationship.house_id).users.each do |user| %>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission', :f => perm, user: user %>
<% end %>
<% end %>
<% User.new(id: 0) do |user| %>
<%= f.fields_for :permissions do |perm| %>
<%= render 'permission', :f => perm, user: user %>
<% end %>
<% end %>
I'm having troubles handling objects that not respect the validation.
I'm building an app in which an user can create a "Trip" model and then add steps to his trip, that I called "Traces". Each added trace prints a new part of a map present in the trip#show action.
The association between models is user has_many trips and trip has_many traces
In the users#show I put a "CREATE NEW TRIP" button linking to the trips#new and here I have the form_for with the field corresponding to the Trip attributes.
When I fill the form correctly everything is ok. When something is missing or wrong (for the validations) I get this error:
NoMethodError in Trips#create
undefined method `model_name' for Array:Class
------ in the trips_controller.rb
def create
#trip = current_user.trips.build(params[:trip])
if #trip.save
# handle a successful save
flash[:success] = 'Trip created!'
redirect_to user_trip_path(#trip, user_id: current_user.id)
else
#trip = []
#feed_items = []
render 'new'
end
end
------ in app/views/trip, in the new.html.erb
h1>Create a trip</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3 general-input">
<%= form_for ([current_user, #trip]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name,'Give a name to your trip ;)' %>
<%= f.text_field :name %>
<%= f.label :trip_start, 'Choose your starting point!' %>
<%= f.text_field :trip_start %>
<%= f.label :departure, 'When are you leaving?' %>
<%= f.date_select :departure, :start_year => Date.current.year %>
<%= f.label :arrive, 'And coming back home?' %>
<%= f.date_select :arrive, :start_year => Date.current.year %>
<%= f.submit 'Create a new trip', class: 'btn btn-primary btn-lg' %>
<% end %>
EDIT 1: problem solving removing #trace=[ ] from trips_controller.rb
EDIT 2:
I also have a similar problem with the creation of a new Trace:
The form for adding a new trace is in the trip#show page.
When I try to create a trace that not respects the validation (e.g. if I leave blank the "destination" field) I get this error:
NoMethodError in Posts#create
undefined method `any?' for nil:NilClass
When I'm on the Trip page where the form for the Traces is placed, the URL is like:
http://localhost:3000/users/2/trips/8
but when I create a not valide Trace it switchs to a path like:
http://localhost:3000/trips/8/posts
I suppose I'm doing something wrong handling the error messages. I probably misunderstood something, even because I'm new to Rails and web programming in general.
Here you are some code parts, hoping it helps to understand my mistake:
------ in the traces_controller.rb
def create
#trip= Trip.find(params[:trip_id])
#trace = #trip.traces.create(params[:trace])
if #trace.save
flash[:success] = 'Trace created!'
redirect_to user_trip_path(#trip, user_id: current_user.id)
else
#trace=[]
render 'trips/show'
end
end
------ in app/views/shared, in the add_trace_form.html.erb
<p>Complete your trip adding a route!</p>
<%= form_for ([#trip, #trip.traces.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="block post-form">
<div class="field ">
<%= f.text_field :end, placeholder: 'Where are you going next?' %>
<%= f.label :arr_day, 'When?' %>
<%= f.date_select :arr_day, :start_year => Date.current.year %>
<%= f.submit 'Add route', class: 'btn btn-primary btn-landing' %>
</div>
</div>
<% end %>
------ in app/views/shared, in the error_messages.html.erb
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |message| %>
<li>* <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
------ in the routes.rb
resources :users do
resources :trips
end
resources :trips do
resources :traces
end
resources :traces
Thanks a lot
i think when you are passing the f.object in locales in render its is passing array not the active record object ,<%= render 'shared/error_messages', object: f.object %>.
Can u check inspecting object in your partial and what class it has.
Try inspecting object.errors.inspect
Try refering http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials