I have a "recipes" table and an "ingredients" table. Each recipe "has_and_belong_to_many" ingredients and each ingredient "has_and_belong_to_many" recipes.
I want to add a link to the ingredient page: "show all recipes which contain this ingredient".
I wrote the following code in my ingredient controller:
def recipes
#ingredient = Ingredient.find(params[:id])
#recipes = #ingredient.recipes
respond_to do |format|
format.html # index.html.erb
format.json { render json: #recipes }
end
end
My problem is that now it expects me to have a "recipes.html.erb" file under the "ingredients" view.
I don't want to create a new view for this, I just want to use the same code I use in the "recipes" view (recipes/index.html.erb).
How can I direct rails to this view?
(I'm using rails 3.x)
Thanks,
Li
Like this:
def recipes
#ingredient = Ingredient.find(params[:id])
#recipes = #ingredient.recipes
respond_to do |format|
format.html { render "recipes/index" }
format.json { render json: #recipes }
end
end
For details, please take a look at the rails guide: http://guides.rubyonrails.org/layouts_and_rendering.html#using-render
Related
I am building a Rails app. And in my app, there are Projects where users can "Follow". When a user follows one of the pages, he/she will get updates if somebody uploads/creates a folder/file.
Below is the screenshot when somebody just created a new folder:
And below is the code for "Create" action in my Folder controller:
def create
#folder = current_user.folders.where(project_id: params[:project_id]).create(folder_params)
respond_to do |format|
if #folder.save
#folder.create_activity :create, owner: current_user, :params => {
:project_id => proc {|controller, project| #folder.project.id},
:project_name => proc {|controller, project| #folder.project.name},
}
format.html { redirect_to #folder.project, notice: 'Folder was successfully created.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { render :new }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
As you can see :project_id and :project_name are the parameters for the public_activity when a new folder being created.
And below is the screenshot on how this parameters value looks like in the database after they were saved:
QUESTION:
So my question is, how do i use this parameters values in my activities_controller?
Here is the code for my activities controller right now:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc").where(owner_id: current_user.following_users, owner_type: "User")
end
end
Instead of using "owner_id:", I want to use the "project_id" value from parameters column. So how can i do this?
Thank you very much in advanced! :)
The parameters field contains a simple yaml dump, so not really easy to search efficiently.
A simple solution would be to use LIKE operator, for instance
PublicActivity::Activity.where("parameters LIKE '%project_id: #{#project.id}%'")
You might want to consider to add custom fields instead.
Thanks for the answer, but I got a better solution than using the parameters value or custom field.
Here is how my activities_controller looks like right now:
class ActivitiesController < ApplicationController
def index
activity_table = PublicActivity::Activity.arel_table
# We want to view all activity of folders related to projects we are follwing
folder_ids = Folder.where(project_id: current_user.following_projects.pluck(:id)).pluck(:id)
# Generate query for all activity related to folders we care about
folders_query = activity_table[:trackable_type].eq('Folder').and(
activity_table[:trackable_id].in(folder_ids)
)
# Generate query for all users that we follow
users_query = activity_table[:owner_id].in(current_user.following_users.pluck(:id))
activity_query = folders_query.or(users_query)
#activities = PublicActivity::Activity.where(activity_query)
end
end
By using this way, I could easily combine the activities from the "Users" and also from the "Projects" that the user follows.
You can modify it to add any other activities such as from the "Comments" or "Voting".
Hope this will help other people out there that are using public_activity gem! :)
I am new to Rails.
I want to render layout(.html.erb file) as well as json data from action of controller.
How can I perform it?
Can I render both of them in single action? how?
This is exactly what respond_to is for. From the Rails Action Controller guide:
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render xml: #users}
format.json { render json: #users}
end
end
end
I have two models: Photo and Product. These are associated via has_many and nested in.
In my 'create' action in my product controller I associate all the photos the user uploaded that have not been linked to a product. (I do it this way because photos are added via ajax).
Now on the edit page. I want to add photos. Which would require me to link photos to a product. Before I did that in the create action. But as you know in Rails there is no real edit action. Because of this there is nowhere in my products controller I join the two.
So, how do I get around this?
P.S. I can't join the two in the photo controller before you ask
product controller
def new
Photo.where(:product_id => nil, :user_id => current_user).delete_all
#product = Product.new
#photo = Photo.new
end
def create
binding.pry
#product = current_user.products.create(params[:product])
if #product.save
Photo.where(:product_id => nil, :user_id => current_user).update_all(:product_id => #product.id)
render "show", notice: "Product created!"
else
render "new", error: "Error submitting product"
end
end
def edit
#product = Product.find(params[:id])
#photo = Photo.new
end
photo controller
def create
#photo = Photo.new(params[:photo])
respond_to do |format|
#photo.user_id = current_user.id
if #photo.save
format.html {
render :json => [#photo.to_jq_image].to_json,
:content_type => 'text/html',
:layout => false
}
format.json { render json: {files: [#photo.to_jq_image]}, status: :created, location: #photo }
else
format.html { render action: "new" }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
There is a method for that
def update
end
exists
It may help if you used the scaffolding at least once to observe a typical rails controller. I'd pay attention to the methods generated.
I am trying to autocomplete a search, the only issues is i am fetching two information. I am following the tutorial here http://railscasts.com/episodes/102-auto-complete-association-revised
Here the issues
def index
#titles = Event.order(:title).where("title like ?", "%#{params[:term]}%")
#customers = Customer.order(:first_name).where("first_name like ?", "%#{params[:term]}%")
render json: #titles.map(&:title)
render json: #customers.map(&:title)
end
If both contain something how can i return both objects.
You have to create a single JSON object which contains both information, like this:
respond_to do |format|
format.json { render json: {titles: #titles.map(&:title), customers: #customers.map(&:title)} }
end
Haven't tested it, but it should work.
I have set up 2 models in Rails:
class Category < ActiveRecord::Base
attr_accessible :name
has_many :platforms
end
and
class Platform < ActiveRecord::Base
attr_accessible :name, :url, :country
validates :name, :presence => true, :length => { :minimum => 5 }
validates :url, :presence => true, :length => { :minimum => 5 }
belongs_to :categories
end
This is my platform controller :
class PlatformsController < ApplicationController
# GET /platforms
# GET /platforms.json
def index
#platforms = Platform.all
#categories = Category.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #platforms }
end
end
# GET /platforms/1
# GET /platforms/1.json
def show
#platform = Platform.find(params[:id])
#categories = Platform.categories
respond_to do |format|
format.html # show.html.erb
format.json { render json: #platform }
end
end
# GET /platforms/new
# GET /platforms/new.json
def new
#platform = Platform.new
#categories = Category.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #platform }
end
end
# GET /platforms/1/edit
def edit
#platform = Platform.find(params[:id])
#categories = Category.find(:all)
end
# POST /platforms
# POST /platforms.json
def create
#platform = Platform.new(params[:platform])
##categories = Category.new(params[:name])
#categories = #platform.categories.create(params[:categories])
respond_to do |format|
if #platform.save
format.html { redirect_to #platform, notice: 'Platform was successfully created.' }
format.json { render json: #platform, status: :created, location: #platform }
else
format.html { render action: "new" }
format.json { render json: #platform.errors, status: :unprocessable_entity }
end
end
end
# PUT /platforms/1
# PUT /platforms/1.json
def update
#platform = Platform.find(params[:id])
#categories = Category.find(:all)
respond_to do |format|
if #platform.update_attributes(params[:platform])
format.html { redirect_to #platform, notice: 'Platform was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #platform.errors, status: :unprocessable_entity }
end
end
end
# DELETE /platforms/1
# DELETE /platforms/1.json
def destroy
#platform = Platform.find(params[:id])
#platform.destroy
respond_to do |format|
format.html { redirect_to platforms_url }
format.json { head :no_content }
end
end
end
I do not understand what I do wrong, but it doesnt correctly assign categories to platforms, and also in the platforms index view, when I try to use :
<%= platform.categories %>
it gives me error cannot find Category with id= "and here the respective id"
I am really confused since I followed tutorial for this one.
I use Rails 3.2.8
Without your view, I can't say for sure what it is you're trying to do exactly. Most importantly, what is in your params[:categories] hash? Given the name, it sounds like you intended for it to be multiple categories. However, your code is written as if you intended it to be a single set of attributes which describe one Category.
Since I can't say for sure what you want to do, I'll answer your question by explaining what you are doing. Maybe that will help you figure out how to fix it.
Your create code currently looks like this:
# POST /platforms
# POST /platforms.json
def create
#platform = Platform.new(params[:platform])
##categories = Category.new(params[:name])
#categories = #platform.categories.create(params[:categories])
The first line creates the new Platform and is easy. Skipping over the comment to the third line. This is probably what's tripping you up.
You are selecting the associations for your newly created Platform and trying to create a new category with attributes as stored in the params[:categories] hash. I'm afraid this is not allowed. (I think it throws an ActiveRecord::RecordNotSaved exception, but I could be wrong.) You can not create on a #platform which hasn't been persisted yet. Instead, I think you want build.
Here is the relevant documentation:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
The difference between create and build is that build just sets up the association without actually saving it to the database yet. create saves it immediately. The nice thing about build is that you don't actually have to save it yourself. It tags along for free when you call #platform.save or #platform.update_attributes. Also, save is automatically wrapped in a transaction, so it won't create the new Category if it fails to create the new Platform for whatever reason.
The next interesting thing is that you are assigning the result of your create to #categories. I don't think this is what you want either. You don't need to save the new Category because it tags along with your #platform. However, if the save of the platform fails, then you are going to re-render your new view with this value of #categories whereas in new you set #categories = Category.all. This could certainly cause some confusion on the new view after a failed create.
In summary, I think your create code should look something like the following.
# POST /platforms
# POST /platforms.json
def create
#platform = Platform.new(params[:platform])
#platform.categories.build(params[:categories])
respond_to do |format|
if #platform.save
format.html { redirect_to #platform, notice: 'Platform was successfully created.' }
format.json { render json: #platform, status: :created, location: #platform }
else
#categories = Category.all
format.html { render action: "new" }
format.json { render json: #platform.errors, status: :unprocessable_entity }
end
end
end
If you're params[:categories] is not a hash of category attributes and is actually a comma delimited string of category names, then you would want to do something like the following instead of my second line above:
params[:categories].split(",").each do |category|
#project.categories.build(name: category)
end
You may also want to check out accepts_nested_attributes_for which can DRY out your controller even more.
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
I hope that helps.