Rails 4: chaining associated objects in Views - ruby-on-rails-4

Ok, I searched all over the web and found no answer.
I am looking for a way to display a name of a 'category' in the show view of a post (I have to mention I'm rookie in Rails).
I have....
a model "Post"
class Post < ActiveRecord::Base
has_many :categories
belongs_to :user
end
a model "Category"
class Category < ActiveRecord::Base
belongs_to :post
end
and the "show" view of the "post" has a line like this
<%= #post.category.name %>
The error message as screen shot:
NoMethodError in Posts#Show - undefined method `category' for #
The "show" action in "Posts" controller:
def show
#post = Post.find(params[:id])
end
I'm building this app along a little outdated training video on udemy. In this video there's in the category model a line with "attr_accessible"
class Category < ActiveRecord::Base
attr_accessible :name <---------------------- this
has_many :posts
end
...but this does no longer exists since Rails 4.0. Is there another way to retrieve the category name of the post?
Thank you in advance :-)

I got the answer. I found out, that every way, to get the data out of the table categories in the view for products won't work. I than thougt, showing the category in the category show view is simple working. With this idea in mind I took the same code, this one:
app/views/categories/show.html.erb
<p>
<strong>Name:</strong>
<%= #category.category_name %> <--------this line
</p>
...from the category show view and put it into the post show view. I than got again an error but different:
--> NoMethodError in Posts#show
Ok, this says the instance variable "#category" isn't available for the post show view. To change that was easy. I copied the object from the categories controller's show action into the posts controller's the show action. Like this:
class PostsController < ApllicationController
.
.
.
def show
#post = Post.find(params[:id])
#category = Category.find(params[:id])
end
And: it works!!!!
But now, is there something wrong to do it like this?
Cheers.

The method category not exists because the Post model has many "categories" not one "category". The Post should have the method "categories". Then if you want to show a first "category" of post in the view:
<%= #post.categories.first.name %>
If you want to show all "categories" of post, then you iterate the collection:
<% #post.categories.each do |category| %>
<%= category.name %>
<% end %>

I tried again and found the real error in my code. the foreign key was not set by Rails. I had to do manually. The table which has a "belongs_to" (in my case the posts table) needs a foreign key added (like category_id).
First creating the migration file:
rails g migration add_foreign_key_to_posts_table
Second adding the migration code to the migration file:
class AddForeignKeyToPostsTable < ActiveRecord::Migration
def change
add_foreign_key :posts, :categories
end
end
Third raking the db migration with:
rake db:migrate
Fourth adding the foreign key for other resources by following steps one to three. Now everything works fine.

Related

Class.where(obj:"someone") with index.html.erb

I've got some problem with method in tittle.
I have got:
model group title:string
model user name:string user:references
In index.html.erb i'm trying to use <=% User.where(group:"Admins) %> and then return on localhost/users (address in RAM i guess) - #<Project:0x007f6f38594af8>. How can i get just name of user where category is Admins?
UPD: I need to list all users of "Admins" group.
Yes, Clear your question. You cannot do <=% User.where(group:"Admins") %> because Group is a model.
But you can scope in Model which will give you list of all users of "Admins" group
class User < ActiveRecord::Base
scope :admin_groups, -> {includes(:groups).where(groups: { title: 'Admin') } }
end
In your view You can call <%= User.admin_groups %>.
Hope this is helpful.

Rails unedited form fields if db column is NULL

Let me try to present a simple example here:
I have db table Orders and a column delivery_address.
<%= form_for #order do |f| %>
<%= f.text_field :delivery_address %>
<% end %>
If no change is made on the form, when the form is submitted the value of Orders.delivery_address changes from NULL to empty value.
and I set a alert notice which looks like:
test#gmail.com changed delivery_address to .
Any suggestion how to prevent updating db fields with NULL values to empty by default with rails update action.
You could do something like this in the model:
# In the Order model
before_validation do
self.delivery_address = nil if delivery_address.blank?
end
I also really don't like that this happens, but the other alternative is to do it on the controller level

Rails 4.2+: Mapping PostgreSQL JSONB nested values to form fields

I have a users table with a settings field of type JSONB (using PostgreSQL 9.5).
I'm trying to create a form on a settings page to update user.settings["notifications"][...] values.
class User < ActiveRecord::Base
end
user = User.create(settings: { notifications: { post_created: true } })
user.settings["notifications"]["post_created"] # => true
To map the nested JSONB values to a form, however, I have to do this:
# views/form.html.erb
<input type="check" name="user[settings][notifications][post_created]" checked="<%= current_user.settings['notifications']['post_created']" %>
class SettingsController
def update
current_user.settings["notifications"]["post_created"] = params["user"]["settings"]["notifications"]["post_created"]
current_user.save
end
end
Is there anyway to utilize the power of Rails form builders such that I can do:
# will not work, undefined attribute settings['notifications']['post_created']...
<%= form_for current_user, url: settings_path, method: "PUT" do |f| %>
<%= f.check_box "settings['notifications']['post_created']" %>
<% end %>
I understand that Rails is trying to map an attribute from the current_user object, and there isn't really an "attribute" named settings['notifications']['post_created'].
But how does one go about mapping nested JSONB values to a form field for CRUD activity?
A workable (but not really feasible) approach is to created virtual attributes for every single nested value I want to work with:
class User
def settings_notifications_post_created
settings["notifications"]["post_created"]
end
def settings_notifications_post_created=(value)
settings["notifications"]["post_created"] = value
end
end
# view...
<%= f.check_box :settings_notifications_post_created %>
But this loses any benefit of a conventional system since I'm manually typing out every attribute. May as well write raw HTML fields and all the getter/setter methods myself...Googling and Stack Overflow haven't been very helpful so far, it seems there aren't very many with experience doing this kind of stuff yet...

Using the Friendly ID gem with Rails, how do you regenerate the slug field?

I'm building a rails app that hosts games. Games belong to categories and thus each category can have many games.
I'm using the Friendly_id gem to generate URL slugs and have the following setup:
Category.rb
class Category < ActiveRecord::Base
extend FriendlyId
friendly_id :name_and_games, use: [:slugged]
has_many :games
def name_and_games
"#{name}-games"
end
end
Games_Controller.rb
...
def category
#category = Category.friendly.find(params[:id])
#categories = Category.all
#games = #category.games.page(params[:page])
render 'games/index'
end
...
Routes.rb
get ':friendly_id', to: "games#category", as: :category
Category_View.html.erb
<% categories.each do |category| %>
<%= link_to category_path(category) do %>
<span><%= pluralize(category.name.capitalize, "Game") %> (<%= category.games.count %>)</span>
<% end %>
<% end %>
The problem is that when I use Friendly_id's slugged module, Rails is generating my urls WITHOUT the "-games" suffix so I end up with URLS like this:
http://localhost:3000/action
http://localhost:3000/adventure
Is there some way to have rails keep the "-games" in my URLs and have it all play nicely such that the "-games" are dropped when it comes time for processing in the model?
Thank you.
So it's:
User.find_each{ |i| i.slug = nil; i.save!; }
Turns out the issue wasn't that Friendly_id wouldn't make the update but that the slug was not getting refreshed.
I had to drop into the Rails console and manually set the "slug" column to nil for each category. Once I did this, Friendly_id reset the "slug" column to reflect my additional text.

Rails 4 - Update Join Table Attributes with has_many through

This is a follow-up of my question: Rails 4 - Access Join Table Value in views
Now I know how to retrieve join table attributes and show them in view. But still I can't find the right approach to edit and update the attribute.
Models:
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, through: :recipe_ingredients
end
class Ingredient < ActiveRecord::Base
has_many :recipe_ingredients
has_many :recipes, through: :recipe_ingredients
end
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
#there is an attribute t.text :amount
end
Recipe#Edit:
...
<%= simple_form_for #recipe do |f| %>
<div class="form-group">
<%= f.input :name, input_html: { class: "form-control"} %>
<%= f.input :description, input_html: { class: "form-control"} %>
<%= f.collection_select(:ingredient_ids, Ingredient.all, :id, :title, {}, {multiple: true}) %>
<!-- reserve for recipe_ingredients.amount -->
</div>
<%= f.submit "Submit", disable_with: 'Submitting...', class: "btn btn-primary"%>
<% end %>
...
As shown above, this is a many-to-many relationship, each recipe may have several ingredients. It works fine and I can choose the right models to associate with (using collection_select). But I have left the work to edit and update join table attributes undone. I have two ideas in my mind:
Make another edit page for editing join model attributes
Ajax? But not quite familiar with
I know the question seems to be trivial, but many solutions are out-dated(Rails 3). Desperate for a Rails 4 solution.
Edit
Intention: I would like to make the creation of Recipe and Ingredient models on their own, which is done. User will see which recipe using the ingredient in Ingredient#show action, which is done also. As to Recipe#show action, there is a slight difference, where user will see which ingredient it is using as well as the amount(join table attribute), which is done in my previous question. The last problem is, I would like to make this attribute editable.
You may want to look into doing nested models combined with the cocoon gem. This will allow you to have a form which updates multiple models at once and it takes care of all the ajax for you. https://github.com/nathanvda/cocoon. I used this gem on a system where the user needed to be able to add one or more answers to a trivia question via dynamic form fields. I think it could work for you as well with giving the user the ability to add one or many RecipeIngredient relations for a recipe. You would be able to add selects dynamically to your form via Cocoon containing a select with the Ingredient model records.