I have a form of a user and a user has many trips (a trip belongs to one user only). When editing the user, i also want to be able to edit the number of people attending the trip. the thing is i only want to show trips that lay in the future. for that i have a method def future_trips inside my user model.
now, i can display the edit page of the user just fine, but it doesn't show the trips. this is my view (in haml):
- simple_form_for model do |f|
= f.input :username, disabled: true
# ... some more stuff...
%hr/
.table-container
%table
%thead
%tr
%th= 'Trip name'
%th= 'Amount people'
%tbody
%p= model.future_trips.size # shows 2
#THIS DOES NOT WORK:
- f.simple_fields_for model.future_trips do |form|
%tr
%td= 'hello'
%td= form.input :attendees
in my user.rb model i put accepts_nested_attributes_for and has_many :trips and in my trips.rb model I have belongs_to :user.
Why is it not working? I thought simple_fields_for worked with an array.
It was a stupid mistake... I typed
- f.simple_fields_for model.future_trips do |form|
but the correct way would be
= f.simple_fields_for :trips, model.future_trips do |form|
So i used - instead of = and forgot :trips. that was the problem
Related
Not sure how to set this relationship up correctly.
3 tables: Users, Posts, Statuses
Models -
User Model
has_many :posts
Post Model
belongs_to :user
has_one :status
Status Model
#Not sure about this.
Tables –
Users: name, email, password_digest
Posts: user_id, status_id, post_title, post_content
Statuses: user_id, status_title, status_active
The user can create their own statuses, so I am not sure if the status should belong to the User or the Post.
In the Users controller, for the new action I have the following to help generate the status options in a dropdown list when making a new Post:
def new
#post = Post.new
#options_statuses = Status.where(:admin_user_id => session[:id])
end
The code to create the new Post(from within a partial):
<%= f.label(:status_id, "Status") %><br/>
<%= f.select(:status_id, #options_statuses.map { |s| [ s.status_title, s.id ] }) %><br/><br/>
<%= f.label(:post_title, "Title") %><br/>
<%= f.text_field(:post_title) %><br/><br/>
<%= f.label(:post_content, "Content") %><br/>
<%= f.text_area(:post_content) %><br/><br/>
The Post info is saved correctly to the database. The problem is when i want to show the posts via the Index or Show actions. Currently I have the following:
<% #posts.each do |post| %>
<%= post.status_id %> - <%= post.created_at %><br/>
<%= post.post_title %> - <%= post.post_content %>
<% end %>
Instead of showing the status_id, I would actually like to display the status_title but am not sure how to do this.
Any help is greatly appreciated.
First of all, since your Post model has a status_id attribute, this means Post should belong_to :status instead of the has_one :status. Status should then either has_one :post or has_many :posts.
Now, for your question: You can achieve this by delegating title to the associated status object. (Hint: think of these objects as objects here -- forget about the database behind them!) Here's how:
# Post model
delegate :title, to: :status, prefix: true
This will define a method behind the scenes that looks like this:
# Post model
def status_title
status.title
end
For more on delegate see the api docs.
I have a model called teacher that I'd like to add ratings to (5 star). Currently, I implement this by adding a ratings nested route (resource rating) inside of my teacher resource. Then I created a model: rating with (id, user_id, teacher_id, ratings, ...). Then I created a form with hidden fields, one of which is called stars. When a user clicks on a star, I use jQuery to send an AJAX request to create/update the rating for that user and teacher.
My confusion is this: I'm having two separate forms on the page. I have a form for writing the reviewers comments. This form has two fields: title, comments (and submit). Then I have the ratings form with hidden fields. Is this the right way to go about something like this? It seems to me that I should really have the ratings model fields somehow embedded in the main review form.
Any help highly appreciated. Thank you.
[EDIT]
I've updated my application so that instead of rating a teacher object, users now rate a comment on a teacher
my setup is something like this:
routes
resources :comments as :teacher_comments do
resource :rating
end
models
comment
has_one :rating
attr_accessible :body, :rating_attributes
accepts_nested_attributes_for :rating
rating
belongs_to :comment
attr_accessible :stars, :user_id, :teacher_id, :comment_id
view
<%= form_for( #comment, :remote => true, :url => teacher_comments_path ) do |tc| %>
<%= tc.text_area :body, :maxlength => 450 %>
<%= tc.fields_for :rating do |builder| %>
<%= builder.text_field :stars %>
<% end %>
<% end %>
I don't see the text_field for the stars. It's just not showing up. Is there something I missed?
Indeed, it's generally better to have all these fields in a single form (good for user experience).
Edit:
You might use the method accepts_nested_attributes_for (as you suggested in the comments below). Put the following in your parent Model (teacher); then you should be able to create a single form to handle inputs for both Models:
in the model:
class Comment < ActiveRecord::Base
has_one :rating
accepts_nested_attributes_for :rating
end
in the controller:
def new
#comment = Comment.new
#comment.rating = Rating.new
end
Ryan Bates gives a detailed screencast on the use of these concepts here: Nested Model Form. I recommend it for users who want to know more ins and outs.
Original:
This means that you'll need to point the form to an action that can handle both types of input. You can still use form_for if you like, but specify an action other than your default (or change the code within the default action in your teacher_controller.rb file):
<%= form_for #teacher, :url => {:action => 'create_and_rate'} do |f| %>
Since rating is a Model distinct from teacher (whose form we just created), you'll want to use the generic _tag form helpers for the rating fields.
<%= text_field_tag :rating, :name %> # rating's fields should use the generic form helper
<%= f.text_field :name %> # teacher's fields can use the specific form helper
Since you are pointing to a non-RESTful action, add it to your routes file.
resources :teacher do
:collection do
post 'create_and_rate' # this will match /teachers/create_and_rate to TeachersController#create_and_rate
end
end
I'm putting up the same question I asked here in activeadmin's issues board on github:
https://github.com/gregbell/active_admin/issues/645
Hi,
I have two different issues.
1: i love the way active admin handles has_many relationships with a simple DSL like so:
ActiveAdmin.register Artist do
form do |f|
f.inputs do
f.input :name
f.input :description
end
f.inputs "ArtistLinks" do
f.has_many :artist_links do |j|
j.inputs :title, :url
end
end
f.buttons
end
end
The ability to add more links at the bottom of the form is great.
However,I have been using a wyiswyg which i can't seem to get working in this format. I've been using/adding it with a partial like so:
ActiveAdmin.register NewsItem do
form :partial => "/news_items/form"
end
/app/views/news_item/_form.html.erb
<%= javascript_include_tag "/javascripts/ckeditor/ckeditor.js" %>
<%= semantic_form_for [:admin, #news_item], :multipart => true do |f| %>
<%= f.inputs :title, :photo, :excerpt %>
<%= cktext_area_tag("news_item[content]", #news_item.content) %>
<%= f.submit %>
<% end %>
However,
in my partial, i can't seem to be able to make the has_many relationship nicely like so:
f.inputs "ArtistLinks" do
f.has_many :artist_links do |j|
j.inputs :title, :url
end
end
Could you either explain to me how to get my wysiwyg which uses a form helper cktext_area_tag into my admin resource or explain to me how to get that nice has_many into my view partial?
Thanks a bunch!
The reason why has_many does not work in partials is because Active Admin tells you to use semantic_form_for when writing your partial. Active Admin extends Formtastic which it uses to generate forms. It does so by creating its own form builder that extends the Formtastic builder and adds, among others, the has_many method. So if you want to use that inside partials you have to use the Active Admin form builder. To do that use active_admin_form_for instead of semantic_form_for.
If you have problems using active_admin_form_for, take a look at my branch which should fix most of the issues (it's still beta - but I'm working on getting it into Active Admin core)
Newbie question, you've been warned!
I'm trying to implement a sample Rails app with a many-to-many association, people owning movies, and I'm trying to figure out how exactly to implement the UI for it. It's my understanding that REST requires everything to be a resource, so in this case "User" (person), "Movie" and "Possession" (the joint table) (oh, the puns).
Now the interesting part, the UX. Let's say I have a user dashboard where all of your movies are listed.
Let's say the user wants to add a movie that he owns. How do you do this in REST? It's trivial with a custom action that one could add to the User controller, but the point is not to go beyond the basic 7 REST actions, right? Therefore I'd have to first do a "new" on a movie and then do a "new" on a possession, which are two operations. How do I collapse them into one?
Basically I feel I'm not quite understanding how to maintain REST as soon as multiple models are involved and would appreciate a tip.
Thanks!
Happily, Rails has some magic just for this common scenario. Assuming a model like this:
class Movie
has_many :users, :through => :possessions
end
Your view:
<%= form_for [current_user, Movie.new] do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<% end %>
Basically this form will POST to MoviesController#create and will pass along current_user.id as a user_id parameter that (the default) MoviesController#create will know to associate with the Movie it creates. Take a look at the documentation for FormBuilder#form_for for more information.
You could also do this the other way around, by the way:
class User
has_many :movies, :through => :possessions
accepts_nested_attributes_for :movies # magic!
end
And the view:
<%= form_for current_user |user_form| %>
<%= user_form.fields_for current_user.movies.build |movie_fields| %>
<%= movie_fields.label :title %>
<%= movie_fields.text_field :title %>
<% end %>
<% end %>
In this case the form will submit to UsersController#update and its parameters will look like this:
{ :id => 123,
:movie => {
:title => "The Red Balloon"
}
}
...and the controller will know to create the Movie object. For more information check the documentation for FormHelper#fields_for.
Read the big update for the latest information.
Hey everyone,
I've got a many-to-many relationship in a rails app that involves three tables: a user table, an interests table, and a join user_interests table that also has a rating value so a user can rate each of their interests on a 1-10 scale.
I am basically looking for a way for a new user to create their rating when they sign up and edit them at a future date along with any of their profile information at the same time.
I tried to follow this question Rails nested form with has_many :through, how to edit attributes of join model? but the problem I'm having is trying to incorporate a select list into the mix and having multiple interests to rate for the user.
Model Code:
user.rb
has_many :user_interests, :dependent => :destroy
has_many :interests, :through => :user_interests, :foreign_key => :user_id
accepts_nested_attributes_for :user_interests
interest.rb
has_many :user_interests, :dependent => :destroy
has_many :users, :through => :user_interests, :foreign_key => :interest_id, :dependent => :destroy
user_interest.rb
belongs_to :user
belongs_to :interest
View Code:
app/views/user/_form.html.erb
<%= form_for(#user) do |form| %>
... user fields
<%= form.fields_for :user_interests do |ui_form| %>
... loop through ALL interests
<% Interest.all.each do |interest| %>
<%= ui_form.select :rating, options_for_select(1..10) %>
<%= ui_form.hidden_field :interest_id, :value => interest.id %>
<% end %>
<% end %>
<% end %>
I also included the following in the new/edit actions in my controller #user.interests.build.build_interest
The problem I'm running into is that only one interest rating is being passed in the params hash when I want to have multiple. Also I am getting an exception thrown by rails
Interest(#2172840620) expected, got Array(#2148226700)
What tiny detail did I miss or get wrong that is causing the problem?
EDIT:
I found a way to force this to work but it requires manually editing the HTML in chrome developer tools, the :name attribute of my form elements are being generated as user[user_interests_attributes][rating] but if I change it to user[user_interests_attributes][][rating] it will work when I update a record. However I can't manually specify the :name of a form element that is tied to a form object. So what can I do to show that multiple interest ratings are being passed instead of just one that rails thinks?
BIG Update:
I got a semi functional version going with some slight changes:
View code:
<% form.fields_for :user_interests do |ui_form| %>
<p>
<%= ui_form.select :rating, options_for_select(1..5), :selected => :rating %>
<%= ui_form.label :interest_title %>
<%= ui_form.hidden_field :interest_id %>
</p>
<% end %>
Controller code:
def new
#user = User.new
Interest.all.each { |int| #user.user_interests.build({ :interest_id => int.id }) }
end
def edit
#user = #current_user
Interest.unrated_by_user_id(#user.id).each { |int| #user.user_interests.build({ :interest_id => int.id }) }
end
Now I am able to edit and get my user_interests updated or created if no rating exists, but I get an error that user is empty when I try to create a new user. Also I am unable to access any of the interest attributes in the form to display the interest the user is actually rating. Can anyone help with those caveats?
You only need #user.interests.build because its a has_many relationship. build_interest is for when there is a has_one/belongs_to relationship.
When using fields_for :user_interests you're telling the User model that an instance of one or more user_interest objects will be in the parameters hash when the user is created/updated. The form is not creating or updating any user_interests but it is sending back an array of user_interest_attributes hashes that represent the user_interests for the user the form references. This is an array of user_interests rating values for which no user_interests exist as you reference them in the form which is the reason you get the error.
Since you are passing a range to the select form helper you aren't actually providing any interests to the form for selection. The select will set a value for the rating column in the user_interests table with a value between 1 and 10. No user_interest exists for the rating to be set on even if the user_interests table has a rating column.
passing :multiple => true in the options hash of the select tag will create a multiple select list but I don't think that is what you want. I think you want many items on a page the user can put an interest rating on.
If you do want a user to be able to select many interests this is how to use fields_for with accepts_nested_attributes_for on a has_many :through relationship:
<%= form_for(#user) do |f| %>
<% f.fields_for :interest_ids do |interest| %>
<ul>
<% Interest.all.each do |choice,i| %>
<li class="selection">
<%= interest.check_box [], { :checked => f.object.user_interest_ids.include?(choice.id) }, choice.id, '' %>
<%= interest.label [], choice.name %>
</li>
<% end %>
</ul>
<% end %>
<% end %>